Commit cc39c13a authored by Tiger Watson's avatar Tiger Watson

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

Add squash commit message template

See merge request gitlab-org/gitlab!74340
parents 304b19a8 c8e78181
......@@ -41,7 +41,6 @@ export default {
rows="7"
@input="$emit('input', $event.target.value)"
></textarea>
<slot name="text-muted"></slot>
</div>
</li>
</template>
......@@ -181,9 +181,16 @@ export default {
return this.mr.canRemoveSourceBranch;
},
commitTemplateHelpPage() {
return helpPagePath('user/project/merge_requests/commit_templates.md', {
anchor: 'merge-commit-message-template',
});
return helpPagePath('user/project/merge_requests/commit_templates.md');
},
commitTemplateHintText() {
if (this.shouldShowSquashEdit && this.shouldShowMergeEdit) {
return this.$options.i18n.mergeAndSquashCommitTemplatesHintText;
}
if (this.shouldShowSquashEdit) {
return this.$options.i18n.squashCommitTemplateHintText;
}
return this.$options.i18n.mergeCommitTemplateHintText;
},
commits() {
if (this.glFeatures.mergeRequestWidgetGraphql) {
......@@ -509,6 +516,12 @@ export default {
mergeCommitTemplateHintText: s__(
'mrWidget|To change this default message, edit the template for merge commit messages. %{linkStart}Learn more.%{linkEnd}',
),
squashCommitTemplateHintText: s__(
'mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}',
),
mergeAndSquashCommitTemplatesHintText: s__(
'mrWidget|To change these default messages, edit the templates for both the merge and squash commit messages. %{linkStart}Learn more.%{linkEnd}',
),
},
};
</script>
......@@ -674,23 +687,22 @@ export default {
:label="__('Merge commit message')"
input-id="merge-message-edit"
class="gl-m-0! gl-p-0!"
>
<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>
/>
<li class="gl-m-0! gl-p-0!">
<p class="form-text text-muted">
<gl-sprintf :message="commitTemplateHintText">
<template #link="{ content }">
<gl-link
:href="commitTemplateHelpPage"
class="inline-link"
target="_blank"
>
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</p>
</li>
</ul>
</div>
<div
......@@ -792,19 +804,18 @@ export default {
v-model="commitMessage"
:label="__('Merge commit message')"
input-id="merge-message-edit"
>
<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>
/>
<li>
<p class="form-text text-muted">
<gl-sprintf :message="commitTemplateHintText">
<template #link="{ content }">
<gl-link :href="commitTemplateHelpPage" class="inline-link" target="_blank">
{{ content }}
</gl-link>
</template>
</gl-sprintf>
</p>
</li>
</ul>
</commits-header>
</template>
......
......@@ -452,6 +452,7 @@ class ProjectsController < Projects::ApplicationController
:packages_enabled,
:service_desk_enabled,
:merge_commit_template,
:squash_commit_template,
project_setting_attributes: project_setting_attributes
] + [project_feature_attributes: project_feature_attributes]
end
......
......@@ -386,6 +386,11 @@ module Types
null: true,
description: 'Template used to create merge commit message in merge requests.'
field :squash_commit_template,
GraphQL::Types::String,
null: true,
description: 'Template used to create squash commit message in merge requests.'
def label(title:)
BatchLoader::GraphQL.for(title).batch(key: project) do |titles, loader, args|
LabelsFinder
......
......@@ -1317,7 +1317,7 @@ class MergeRequest < ApplicationRecord
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
return ::Gitlab::MergeRequests::CommitMessageGenerator.new(merge_request: self).merge_message
end
closes_issues_references = visible_closing_issues_for.map do |issue|
......@@ -1340,6 +1340,10 @@ class MergeRequest < ApplicationRecord
end
def default_squash_commit_message
if self.target_project.squash_commit_template.present?
return ::Gitlab::MergeRequests::CommitMessageGenerator.new(merge_request: self).squash_message
end
title
end
......
......@@ -452,6 +452,7 @@ class Project < ApplicationRecord
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 :squash_commit_template, :squash_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
......
......@@ -13,6 +13,7 @@ class ProjectSetting < ApplicationRecord
self.primary_key = :project_id
validates :merge_commit_template, length: { maximum: 500 }
validates :squash_commit_template, length: { maximum: 500 }
def squash_enabled_by_default?
%w[always default_on].include?(squash_option)
......
......@@ -12,6 +12,6 @@
%p.form-text.text-muted
= s_('ProjectSettings|Maximum 500 characters.')
= s_('ProjectSettings|Supported variables:')
- Gitlab::MergeRequests::MergeCommitMessage::PLACEHOLDERS.keys.each do |placeholder|
- Gitlab::MergeRequests::CommitMessageGenerator::PLACEHOLDERS.keys.each do |placeholder|
%code
= "%{#{placeholder}}".html_safe
......@@ -12,5 +12,7 @@
= render 'projects/merge_request_merge_commit_template', project: @project, form: form
= render 'projects/merge_request_squash_commit_template', project: @project, form: form
- if @project.forked?
= render 'projects/merge_request_target_project_settings', project: @project, form: form
- form = local_assigns.fetch(:form)
.form-group
%b= s_('ProjectSettings|Squash commit message template')
%p.text-secondary
- configure_the_squash_commit_message_help_link_url = help_page_path('user/project/merge_requests/commit_templates.md', anchor: 'squash-commit-message-template')
- configure_the_squash_commit_message_help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: configure_the_squash_commit_message_help_link_url }
= s_('ProjectSettings|The commit message used when squashing commits. %{link_start}Learn more about syntax and variables.%{link_end}').html_safe % { link_start: configure_the_squash_commit_message_help_link_start, link_end: '</a>'.html_safe }
.mb-2
= form.text_area :squash_commit_template, class: 'form-control gl-form-input', rows: 8, maxlength: 500, placeholder: '%{title}'
%p.form-text.text-muted
= s_('ProjectSettings|Maximum 500 characters.')
= s_('ProjectSettings|Supported variables:')
- Gitlab::MergeRequests::CommitMessageGenerator::PLACEHOLDERS.keys.each do |placeholder|
%code
= "%{#{placeholder}}".html_safe
# frozen_string_literal: true
class AddSquashCommitTemplateToProjectSettings < Gitlab::Database::Migration[1.0]
enable_lock_retries!
def change
add_column :project_settings, :squash_commit_template, :text # rubocop:disable Migration/AddLimitToTextColumns
end
end
# frozen_string_literal: true
class AddSquashCommitTemplateLimitToProjectSettings < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
def up
add_text_limit :project_settings, :squash_commit_template, 500
end
def down
remove_text_limit :project_settings, :squash_commit_template
end
end
d78fe687517e14ff67dc76eff63391e33b73d29446d2a0445595175c7cd6806a
\ No newline at end of file
c8ed7f8c0f818156dba9c25be848da97d4eb6dbf0aa9c48f87e940f3ca0967d9
\ No newline at end of file
......@@ -18299,7 +18299,9 @@ CREATE TABLE project_settings (
warn_about_potentially_unwanted_characters boolean DEFAULT true NOT NULL,
merge_commit_template text,
has_shimo boolean DEFAULT false NOT NULL,
squash_commit_template text,
CONSTRAINT check_3a03e7557a CHECK ((char_length(previous_default_branch) <= 4096)),
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))
);
......@@ -12867,6 +12867,7 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="projectservicedeskenabled"></a>`serviceDeskEnabled` | [`Boolean`](#boolean) | Indicates if the project has service desk enabled. |
| <a id="projectsharedrunnersenabled"></a>`sharedRunnersEnabled` | [`Boolean`](#boolean) | Indicates if shared runners are enabled for the project. |
| <a id="projectsnippetsenabled"></a>`snippetsEnabled` | [`Boolean`](#boolean) | Indicates if Snippets are enabled for the current user. |
| <a id="projectsquashcommittemplate"></a>`squashCommitTemplate` | [`String`](#string) | Template used to create squash commit message in merge requests. |
| <a id="projectsquashreadonly"></a>`squashReadOnly` | [`Boolean!`](#boolean) | Indicates if `squashReadOnly` is enabled. |
| <a id="projectsshurltorepo"></a>`sshUrlToRepo` | [`String`](#string) | URL to connect to the project via SSH. |
| <a id="projectstarcount"></a>`starCount` | [`Int!`](#int) | Number of times the project has been starred. |
......@@ -183,6 +183,7 @@ When the user is authenticated and `simple` is not set this returns something li
"autoclose_referenced_issues": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_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": {
......@@ -300,6 +301,7 @@ When the user is authenticated and `simple` is not set this returns something li
"autoclose_referenced_issues": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"statistics": {
"commit_count": 12,
"storage_size": 2066080,
......@@ -470,6 +472,7 @@ GET /users/:user_id/projects
"autoclose_referenced_issues": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_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": {
......@@ -587,6 +590,7 @@ GET /users/:user_id/projects
"autoclose_referenced_issues": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"statistics": {
"commit_count": 12,
"storage_size": 2066080,
......@@ -714,6 +718,7 @@ Example response:
"autoclose_referenced_issues": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"statistics": {
"commit_count": 37,
"storage_size": 1038090,
......@@ -826,6 +831,7 @@ Example response:
"autoclose_referenced_issues": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
"statistics": {
"commit_count": 12,
"storage_size": 2066080,
......@@ -994,6 +1000,7 @@ GET /projects/:id
"autoclose_referenced_issues": true,
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_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" ],
......@@ -1307,6 +1314,7 @@ POST /projects/user/:user_id
| `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.)_ |
| `squash_commit_template` | string | **{dotted-circle}** No | [Template](../user/project/merge_requests/commit_templates.md#squash-commit-message-template) used to create squash commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345275) in GitLab 14.6.)_ |
| `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. |
......
......@@ -31,7 +31,7 @@ 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)
![Custom commit message for merge commit](img/merge_commit_message_template_v14_5.png)
You can use static text and following variables:
......@@ -49,3 +49,18 @@ Empty variables that are the only word in a line will be removed along with all
Merge commit template field has a limit of 500 characters. This limit only applies to the template
itself.
## Squash commit message template
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345275) in GitLab 14.6.
As a project maintainer, you're able to configure squash commit message template. It will be used during merge with
squash to create squash commit message. It uses the same syntax and variables as merge commit message template.
![Custom commit message for squash commit](img/squash_commit_message_template_v14_6.png)
Default squash commit message can be recreated using following template:
```plaintext
%{title}
```
......@@ -28,9 +28,9 @@ NOTE:
The squashed commit in this example is followed by a merge commit, because the merge method for this repository uses a merge commit. You can disable merge commits in
**Project Settings > General > Merge requests > Merge method > Fast-forward merge**.
The squashed commit's default commit message is taken from the merge request title.
The squashed commit's default commit message is taken from the merge request title. It can be changed using [squash commit message template](commit_templates.md#squash-commit-message-template).
It can be customized before merging a merge request.
It can also be customized before merging a merge request.
![A squash commit message editor](img/squash_mr_message.png)
......
......@@ -315,7 +315,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 [merge and squash commit message templates](../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
......
......@@ -15,6 +15,8 @@
= render_ce 'projects/merge_request_merge_commit_template', project: @project, form: form
= render_ce 'projects/merge_request_squash_commit_template', project: @project, form: form
- if @project.forked?
= render_ce 'projects/merge_request_target_project_settings', project: @project, form: form
......
......@@ -115,6 +115,7 @@ module API
expose :squash_option
expose :suggestion_commit_message
expose :merge_commit_template
expose :squash_commit_template
expose :statistics, using: 'API::Entities::ProjectStatistics', if: -> (project, options) {
options[:statistics] && Ability.allowed?(options[:current_user], :read_statistics, project)
}
......
......@@ -62,6 +62,7 @@ module API
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 :squash_commit_template, type: String, desc: 'Template used to create squash 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'
......@@ -162,6 +163,7 @@ module API
:avatar,
:suggestion_commit_message,
:merge_commit_template,
:squash_commit_template,
:repository_storage,
:compliance_framework_setting,
:packages_enabled,
......
# frozen_string_literal: true
module Gitlab
module MergeRequests
class MergeCommitMessage
class CommitMessageGenerator
def initialize(merge_request:)
@merge_request = merge_request
end
def message
def merge_message
return unless @merge_request.target_project.merge_commit_template.present?
message = @merge_request.target_project.merge_commit_template
message = message.delete("\r")
replace_placeholders(@merge_request.target_project.merge_commit_template)
end
# 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
def squash_message
return unless @merge_request.target_project.squash_commit_template.present?
Gitlab::StringPlaceholderReplacer
.replace_string_placeholders(message, PLACEHOLDERS_REGEX) do |key|
PLACEHOLDERS[key].call(merge_request)
end
replace_placeholders(@merge_request.target_project.squash_commit_template)
end
private
......@@ -55,6 +45,26 @@ module Gitlab
BLANK_PLACEHOLDERS_REGEXES = (PLACEHOLDERS.map do |key, value|
[key, Regexp.new("[\n\r]+%{#{Regexp.escape(key)}}$")]
end).to_h.freeze
def replace_placeholders(message)
# convert CRLF to LF
message = message.delete("\r")
# 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
end
end
end
......@@ -27449,6 +27449,9 @@ msgstr ""
msgid "ProjectSettings|Snippets"
msgstr ""
msgid "ProjectSettings|Squash commit message template"
msgstr ""
msgid "ProjectSettings|Squash commits when merging"
msgstr ""
......@@ -27473,6 +27476,9 @@ 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 commit message used when squashing commits. %{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 ""
......@@ -41711,9 +41717,15 @@ 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 these default messages, edit the templates for both the merge and squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "mrWidget|To change this default message, edit the template for merge commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "mrWidget|To change this default message, edit the template for squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "mrWidget|To merge, a Jira issue key must be mentioned in the title or description."
msgstr ""
......
......@@ -7,19 +7,26 @@ RSpec.describe 'Merge request < User customizes merge commit message', :js do
let(:user) { project.creator }
let(:issue_1) { create(:issue, project: project)}
let(:issue_2) { create(:issue, project: project)}
let(:source_branch) { 'csv' }
let(:target_branch) { 'master' }
let(:squash) { false }
let(:merge_request) do
create(
:merge_request,
:simple,
source_project: project,
description: "Description\n\nclosing #{issue_1.to_reference}, #{issue_2.to_reference}"
target_project: project,
source_branch: source_branch,
target_branch: target_branch,
description: "Description\n\nclosing #{issue_1.to_reference}, #{issue_2.to_reference}",
squash: squash
)
end
let(:textbox) { page.find(:css, '#merge-message-edit', visible: false) }
let(:default_message) do
let(:merge_textbox) { page.find(:css, '#merge-message-edit', visible: false) }
let(:squash_textbox) { page.find(:css, '#squash-message-edit', visible: false) }
let(:default_merge_commit_message) do
[
"Merge branch 'feature' into 'master'",
"Merge branch '#{source_branch}' into '#{target_branch}'",
merge_request.title,
"Closes #{issue_1.to_reference} and #{issue_2.to_reference}",
"See merge request #{merge_request.to_reference(full: true)}"
......@@ -35,8 +42,8 @@ RSpec.describe 'Merge request < User customizes merge commit message', :js 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)
expect(merge_textbox).to be_visible
expect(merge_textbox.value).to eq(default_merge_commit_message)
end
context 'when target project has merge commit template set' do
......@@ -45,8 +52,34 @@ RSpec.describe 'Merge request < User customizes merge commit message', :js do
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)
expect(merge_textbox).to be_visible
expect(merge_textbox.value).to eq(merge_request.title)
end
end
context 'when squash is performed' do
let(:squash) { true }
it 'has default message with merge request title' do
expect(page).not_to have_selector('#squash-message-edit')
first('.js-mr-widget-commits-count').click
expect(squash_textbox).to be_visible
expect(merge_textbox).to be_visible
expect(squash_textbox.value).to eq(merge_request.title)
expect(merge_textbox.value).to eq(default_merge_commit_message)
end
context 'when target project has squash commit template set' do
let(:project) { create(:project, :public, :repository, squash_commit_template: '%{description}') }
it 'uses squash commit template' do
expect(page).not_to have_selector('#squash-message-edit')
first('.js-mr-widget-commits-count').click
expect(squash_textbox).to be_visible
expect(merge_textbox).to be_visible
expect(squash_textbox.value).to eq(merge_request.description)
expect(merge_textbox.value).to eq(default_merge_commit_message)
end
end
end
end
......@@ -3,7 +3,6 @@ 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', () => {
......@@ -64,7 +63,6 @@ describe('Commits edit component', () => {
beforeEach(() => {
createComponent({
header: `<div class="test-header">${testCommitMessage}</div>`,
'text-muted': `<p class="test-text-muted">${testTextMuted}</p>`,
});
});
......@@ -74,12 +72,5 @@ describe('Commits edit component', () => {
expect(headerSlotElement.exists()).toBe(true);
expect(headerSlotElement.text()).toBe(testCommitMessage);
});
it('renders text-muted slot correctly', () => {
const textMutedElement = wrapper.find('.test-text-muted');
expect(textMutedElement.exists()).toBe(true);
expect(textMutedElement.text()).toBe(testTextMuted);
});
});
});
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import { GlSprintf } from '@gitlab/ui';
import simplePoll from '~/lib/utils/simple_poll';
import CommitEdit from '~/vue_merge_request_widget/components/states/commit_edit.vue';
import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/commit_message_dropdown.vue';
......@@ -487,6 +488,7 @@ describe('ReadyToMerge', () => {
const findCommitEditElements = () => wrapper.findAll(CommitEdit);
const findCommitDropdownElement = () => wrapper.find(CommitMessageDropdown);
const findFirstCommitEditLabel = () => findCommitEditElements().at(0).props('label');
const findTipLink = () => wrapper.find(GlSprintf);
describe('squash checkbox', () => {
it('should be rendered when squash before merge is enabled and there is more than 1 commit', () => {
......@@ -751,6 +753,12 @@ describe('ReadyToMerge', () => {
expect(findCommitDropdownElement().exists()).toBeTruthy();
});
});
it('renders a tip including a link to docs on templates', () => {
createComponent();
expect(findTipLink().exists()).toBe(true);
});
});
describe('Merge request project settings', () => {
......
......@@ -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 merge_commit_template
ci_template timelogs merge_commit_template squash_commit_template
]
expect(described_class).to include_graphql_fields(*expected_fields)
......
......@@ -563,6 +563,7 @@ Project:
- autoclose_referenced_issues
- suggestion_commit_message
- merge_commit_template
- squash_commit_template
ProjectTracingSetting:
- external_url
Author:
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::MergeRequests::CommitMessageGenerator do
let(:merge_commit_template) { nil }
let(:squash_commit_template) { nil }
let(:project) do
create(
:project,
:public,
:repository,
merge_commit_template: merge_commit_template,
squash_commit_template: squash_commit_template
)
end
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) }
shared_examples_for 'commit message with template' do |message_template_name|
it 'returns nil when template is not set in target project' do
expect(result_message).to be_nil
end
context 'when project has custom commit template' do
let(message_template_name) { <<~MSG.rstrip }
%{title}
See merge request %{reference}
MSG
it 'uses custom template' do
expect(result_message).to eq <<~MSG.rstrip
Bugfix
See merge request #{merge_request.to_reference(full: true)}
MSG
end
end
context 'when project has commit template with closed issues' do
let(message_template_name) { <<~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(result_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(result_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 commit template with description' do
let(message_template_name) { <<~MSG.rstrip }
Merge branch '%{source_branch}' into '%{target_branch}'
%{title}
%{description}
See merge request %{reference}
MSG
it 'uses template' do
expect(result_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(result_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(result_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(result_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 commit template contains placeholder in the middle or beginning of the line' do
let(message_template_name) { <<~MSG.rstrip }
Merge branch '%{source_branch}' into '%{target_branch}'
%{description} %{title}
See merge request %{reference}
MSG
it 'uses custom template' do
expect(result_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(result_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 project has template with CRLF newlines' do
let(message_template_name) do
"Merge branch '%{source_branch}' into '%{target_branch}'\r\n\r\n%{title}\r\n\r\n%{description}\r\n\r\nSee merge request %{reference}"
end
it 'converts it to LF newlines' do
expect(result_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(result_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
describe '#merge_message' do
let(:result_message) { subject.merge_message }
it_behaves_like 'commit message with template', :merge_commit_template
end
describe '#squash_message' do
let(:result_message) { subject.squash_message }
it_behaves_like 'commit message with template', :squash_commit_template
end
end
# 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
context 'when project has template with CRLF newlines' do
let(:merge_commit_template) do
"Merge branch '%{source_branch}' into '%{target_branch}'\r\n\r\n%{title}\r\n\r\n%{description}\r\n\r\nSee merge request %{reference}"
end
it 'converts it to LF newlines' 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
end
end
......@@ -178,6 +178,13 @@ RSpec.describe MergeRequest, factory_default: :keep do
it 'returns the merge request title' do
expect(subject.default_squash_commit_message).to eq(subject.title)
end
it 'uses template from target project' do
subject.target_project.squash_commit_template = 'Squashed branch %{source_branch} into %{target_branch}'
expect(subject.default_squash_commit_message)
.to eq('Squashed branch master into feature')
end
end
describe 'modules' do
......
......@@ -92,6 +92,22 @@ RSpec.describe 'projects/edit' do
end
end
context 'squash template' do
it 'displays a placeholder if none is set' do
render
expect(rendered).to have_field('project[squash_commit_template]', placeholder: '%{title}')
end
it 'displays the user entered value' do
project.update!(squash_commit_template: '%{first_multiline_commit}')
render
expect(rendered).to have_field('project[squash_commit_template]', with: '%{first_multiline_commit}')
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