Commit 65d0fec0 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab-ce master

parents aa2845a6 0f04d4b2
...@@ -14,6 +14,10 @@ export default { ...@@ -14,6 +14,10 @@ export default {
type: Boolean, type: Boolean,
required: true, required: true,
}, },
isFastForwardEnabled: {
type: Boolean,
required: true,
},
commitsCount: { commitsCount: {
type: Number, type: Number,
required: false, required: false,
...@@ -37,16 +41,22 @@ export default { ...@@ -37,16 +41,22 @@ export default {
return n__(__('%d commit'), __('%d commits'), this.isSquashEnabled ? 1 : this.commitsCount); return n__(__('%d commit'), __('%d commits'), this.isSquashEnabled ? 1 : this.commitsCount);
}, },
modifyLinkMessage() { modifyLinkMessage() {
return this.isSquashEnabled ? __('Modify commit messages') : __('Modify merge commit'); if (this.isFastForwardEnabled) return __('Modify commit message');
else if (this.isSquashEnabled) return __('Modify commit messages');
return __('Modify merge commit');
}, },
ariaLabel() { ariaLabel() {
return this.expanded ? __('Collapse') : __('Expand'); return this.expanded ? __('Collapse') : __('Expand');
}, },
message() { message() {
const message = this.isFastForwardEnabled
? s__('mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}.')
: s__(
'mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}.',
);
return sprintf( return sprintf(
s__( message,
'mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}.',
),
{ {
commitCount: `<strong class="commits-count-message">${this.commitsCountMessage}</strong>`, commitCount: `<strong class="commits-count-message">${this.commitsCountMessage}</strong>`,
mergeCommitCount: `<strong>${s__('mrWidgetCommitsAdded|1 merge commit')}</strong>`, mergeCommitCount: `<strong>${s__('mrWidgetCommitsAdded|1 merge commit')}</strong>`,
......
...@@ -117,6 +117,12 @@ export default { ...@@ -117,6 +117,12 @@ export default {
shouldShowMergeControls() { shouldShowMergeControls() {
return this.mr.isMergeAllowed || this.shouldShowMergeWhenPipelineSucceedsText; return this.mr.isMergeAllowed || this.shouldShowMergeWhenPipelineSucceedsText;
}, },
shouldShowSquashEdit() {
return this.squashBeforeMerge && this.shouldShowSquashBeforeMerge;
},
shouldShowMergeEdit() {
return !this.mr.ffOnlyEnabled;
},
}, },
methods: { methods: {
updateMergeCommitMessage(includeDescription) { updateMergeCommitMessage(includeDescription) {
...@@ -325,43 +331,44 @@ export default { ...@@ -325,43 +331,44 @@ export default {
<div v-if="mr.ffOnlyEnabled" class="mr-fast-forward-message"> <div v-if="mr.ffOnlyEnabled" class="mr-fast-forward-message">
{{ __('Fast-forward merge without a merge commit') }} {{ __('Fast-forward merge without a merge commit') }}
</div> </div>
<template v-else> <commits-header
<commits-header v-if="shouldShowSquashEdit || shouldShowMergeEdit"
:is-squash-enabled="squashBeforeMerge" :is-squash-enabled="squashBeforeMerge"
:commits-count="mr.commitsCount" :commits-count="mr.commitsCount"
:target-branch="mr.targetBranch" :target-branch="mr.targetBranch"
> :is-fast-forward-enabled="mr.ffOnlyEnabled"
<ul class="border-top content-list commits-list flex-list"> >
<commit-edit <ul class="border-top content-list commits-list flex-list">
v-if="squashBeforeMerge && shouldShowSquashBeforeMerge" <commit-edit
v-if="shouldShowSquashEdit"
v-model="squashCommitMessage"
:label="__('Squash commit message')"
input-id="squash-message-edit"
squash
>
<commit-message-dropdown
slot="header"
v-model="squashCommitMessage" v-model="squashCommitMessage"
:label="__('Squash commit message')" :commits="mr.commits"
input-id="squash-message-edit" />
squash </commit-edit>
> <commit-edit
<commit-message-dropdown v-if="shouldShowMergeEdit"
slot="header" v-model="commitMessage"
v-model="squashCommitMessage" :label="__('Merge commit message')"
:commits="mr.commits" input-id="merge-message-edit"
>
<label slot="checkbox">
<input
id="include-description"
type="checkbox"
@change="updateMergeCommitMessage($event.target.checked)"
/> />
</commit-edit> {{ __('Include merge request description') }}
<commit-edit </label>
v-model="commitMessage" </commit-edit>
:label="__('Merge commit message')" </ul>
input-id="merge-message-edit" </commits-header>
>
<label slot="checkbox">
<input
id="include-description"
type="checkbox"
@change="updateMergeCommitMessage($event.target.checked)"
/>
{{ __('Include merge request description') }}
</label>
</commit-edit>
</ul>
</commits-header>
</template>
</template> </template>
</div> </div>
</template> </template>
...@@ -28,7 +28,8 @@ class PipelineEntity < Grape::Entity ...@@ -28,7 +28,8 @@ class PipelineEntity < Grape::Entity
expose :can_retry?, as: :retryable expose :can_retry?, as: :retryable
expose :can_cancel?, as: :cancelable expose :can_cancel?, as: :cancelable
expose :failure_reason?, as: :failure_reason expose :failure_reason?, as: :failure_reason
expose :detached_merge_request_pipeline?, as: :detached expose :detached_merge_request_pipeline?, as: :detached_merge_request_pipeline
expose :merge_request_pipeline?, as: :merge_request_pipeline
end end
expose :details do expose :details do
......
...@@ -267,7 +267,7 @@ ...@@ -267,7 +267,7 @@
= _('Repository') = _('Repository')
- if template_exists?('admin/application_settings/templates') - if template_exists?('admin/application_settings/templates')
= nav_link(path: 'application_settings#templates') do = nav_link(path: 'application_settings#templates') do
= link_to templates_admin_application_settings_path, title: _('Templates') do = link_to templates_admin_application_settings_path, title: _('Templates'), class: 'qa-admin-settings-template-item' do
%span %span
= _('Templates') = _('Templates')
= nav_link(path: 'application_settings#ci_cd') do = nav_link(path: 'application_settings#ci_cd') do
......
---
title: Allow modifying squash commit message for fast-forward only merge method
merge_request: 26017
author:
type: fixed
---
title: Add merge request pipeline flag to pipeline entity
merge_request: 25846
author:
type: added
...@@ -12042,6 +12042,9 @@ msgstr "" ...@@ -12042,6 +12042,9 @@ msgstr ""
msgid "mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}." msgid "mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}."
msgstr "" msgstr ""
msgid "mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}."
msgstr ""
msgid "mrWidgetCommitsAdded|1 merge commit" msgid "mrWidgetCommitsAdded|1 merge commit"
msgstr "" msgstr ""
......
...@@ -3,7 +3,7 @@ module QA ...@@ -3,7 +3,7 @@ module QA
module Component module Component
module Select2 module Select2
def select_item(item_text) def select_item(item_text)
find('.select2-result-label', text: item_text).click find('.select2-result-label', text: item_text, match: :prefer_exact).click
end end
def clear_current_selection_if_present def clear_current_selection_if_present
......
...@@ -25,11 +25,14 @@ module QA ...@@ -25,11 +25,14 @@ module QA
end end
def choose_test_namespace def choose_test_namespace
choose_namespace(Runtime::Namespace.path)
end
def choose_namespace(namespace)
retry_on_exception do retry_on_exception do
click_body click_body
click_element :project_namespace_select click_element :project_namespace_select
search_and_select(namespace)
search_and_select(Runtime::Namespace.path)
end end
end end
......
...@@ -101,17 +101,36 @@ FactoryBot.define do ...@@ -101,17 +101,36 @@ FactoryBot.define do
end end
end end
trait :with_merge_request_pipeline do trait :with_detached_merge_request_pipeline do
after(:build) do |merge_request| after(:build) do |merge_request|
merge_request.merge_request_pipelines << build(:ci_pipeline, merge_request.merge_request_pipelines << build(:ci_pipeline,
source: :merge_request_event, source: :merge_request_event,
merge_request: merge_request, merge_request: merge_request,
project: merge_request.source_project, project: merge_request.source_project,
ref: merge_request.source_branch, ref: merge_request.ref_path,
sha: merge_request.source_branch_sha) sha: merge_request.source_branch_sha)
end end
end end
trait :with_merge_request_pipeline do
transient do
merge_sha { 'test-merge-sha' }
source_sha { source_branch_sha }
target_sha { target_branch_sha }
end
after(:build) do |merge_request, evaluator|
merge_request.merge_request_pipelines << create(:ci_pipeline,
source: :merge_request_event,
merge_request: merge_request,
project: merge_request.source_project,
ref: merge_request.merge_ref_path,
sha: evaluator.merge_sha,
source_sha: evaluator.source_sha,
target_sha: evaluator.target_sha)
end
end
trait :deployed_review_app do trait :deployed_review_app do
target_branch 'pages-deploy-target' target_branch 'pages-deploy-target'
......
...@@ -15,6 +15,7 @@ describe('Commits header component', () => { ...@@ -15,6 +15,7 @@ describe('Commits header component', () => {
isSquashEnabled: false, isSquashEnabled: false,
targetBranch: 'master', targetBranch: 'master',
commitsCount: 5, commitsCount: 5,
isFastForwardEnabled: false,
...props, ...props,
}, },
}); });
...@@ -31,6 +32,27 @@ describe('Commits header component', () => { ...@@ -31,6 +32,27 @@ describe('Commits header component', () => {
const findTargetBranchMessage = () => wrapper.find('.label-branch'); const findTargetBranchMessage = () => wrapper.find('.label-branch');
const findModifyButton = () => wrapper.find('.modify-message-button'); const findModifyButton = () => wrapper.find('.modify-message-button');
describe('when fast-forward is enabled', () => {
beforeEach(() => {
createComponent({
isFastForwardEnabled: true,
isSquashEnabled: true,
});
});
it('has commits count message showing 1 commit', () => {
expect(findCommitsCountMessage().text()).toBe('1 commit');
});
it('has button with modify commit message', () => {
expect(findModifyButton().text()).toBe('Modify commit message');
});
it('does not have merge commit part of the message', () => {
expect(findHeaderWrapper().text()).not.toContain('1 merge commit');
});
});
describe('when collapsed', () => { describe('when collapsed', () => {
it('toggle has aria-label equal to Expand', () => { it('toggle has aria-label equal to Expand', () => {
createComponent(); createComponent();
...@@ -78,6 +100,10 @@ describe('Commits header component', () => { ...@@ -78,6 +100,10 @@ describe('Commits header component', () => {
expect(findTargetBranchMessage().text()).toBe('master'); expect(findTargetBranchMessage().text()).toBe('master');
}); });
it('does has merge commit part of the message', () => {
expect(findHeaderWrapper().text()).toContain('1 merge commit');
});
}); });
describe('when expanded', () => { describe('when expanded', () => {
......
...@@ -18,6 +18,7 @@ const createTestMr = customConfig => { ...@@ -18,6 +18,7 @@ const createTestMr = customConfig => {
isPipelinePassing: false, isPipelinePassing: false,
isMergeAllowed: true, isMergeAllowed: true,
onlyAllowMergeIfPipelineSucceeds: false, onlyAllowMergeIfPipelineSucceeds: false,
ffOnlyEnabled: false,
hasCI: false, hasCI: false,
ciStatus: null, ciStatus: null,
sha: '12345678', sha: '12345678',
...@@ -624,6 +625,10 @@ describe('ReadyToMerge', () => { ...@@ -624,6 +625,10 @@ describe('ReadyToMerge', () => {
const findCommitsHeaderElement = () => wrapper.find(CommitsHeader); const findCommitsHeaderElement = () => wrapper.find(CommitsHeader);
const findCommitEditElements = () => wrapper.findAll(CommitEdit); const findCommitEditElements = () => wrapper.findAll(CommitEdit);
const findCommitDropdownElement = () => wrapper.find(CommitMessageDropdown); const findCommitDropdownElement = () => wrapper.find(CommitMessageDropdown);
const findFirstCommitEditLabel = () =>
findCommitEditElements()
.at(0)
.props('label');
describe('squash checkbox', () => { describe('squash checkbox', () => {
it('should be rendered when squash before merge is enabled and there is more than 1 commit', () => { it('should be rendered when squash before merge is enabled and there is more than 1 commit', () => {
...@@ -648,31 +653,129 @@ describe('ReadyToMerge', () => { ...@@ -648,31 +653,129 @@ describe('ReadyToMerge', () => {
}); });
describe('commits count collapsible header', () => { describe('commits count collapsible header', () => {
it('should be rendered if fast-forward is disabled', () => { it('should be rendered when fast-forward is disabled', () => {
createLocalComponent(); createLocalComponent();
expect(findCommitsHeaderElement().exists()).toBeTruthy(); expect(findCommitsHeaderElement().exists()).toBeTruthy();
}); });
it('should not be rendered if fast-forward is enabled', () => { describe('when fast-forward is enabled', () => {
createLocalComponent({ mr: { ffOnlyEnabled: true } }); it('should be rendered if squash and squash before are enabled and there is more than 1 commit', () => {
createLocalComponent({
mr: {
ffOnlyEnabled: true,
enableSquashBeforeMerge: true,
squash: true,
commitsCount: 2,
},
});
expect(findCommitsHeaderElement().exists()).toBeTruthy();
});
it('should not be rendered if squash before merge is disabled', () => {
createLocalComponent({
mr: {
ffOnlyEnabled: true,
enableSquashBeforeMerge: false,
squash: true,
commitsCount: 2,
},
});
expect(findCommitsHeaderElement().exists()).toBeFalsy();
});
it('should not be rendered if squash is disabled', () => {
createLocalComponent({
mr: {
ffOnlyEnabled: true,
squash: false,
enableSquashBeforeMerge: true,
commitsCount: 2,
},
});
expect(findCommitsHeaderElement().exists()).toBeFalsy();
});
it('should not be rendered if commits count is 1', () => {
createLocalComponent({
mr: {
ffOnlyEnabled: true,
squash: true,
enableSquashBeforeMerge: true,
commitsCount: 1,
},
});
expect(findCommitsHeaderElement().exists()).toBeFalsy(); expect(findCommitsHeaderElement().exists()).toBeFalsy();
});
}); });
}); });
describe('commits edit components', () => { describe('commits edit components', () => {
describe('when fast-forward merge is enabled', () => {
it('should not be rendered if squash is disabled', () => {
createLocalComponent({
mr: {
ffOnlyEnabled: true,
squash: false,
enableSquashBeforeMerge: true,
commitsCount: 2,
},
});
expect(findCommitEditElements().length).toBe(0);
});
it('should not be rendered if squash before merge is disabled', () => {
createLocalComponent({
mr: {
ffOnlyEnabled: true,
squash: true,
enableSquashBeforeMerge: false,
commitsCount: 2,
},
});
expect(findCommitEditElements().length).toBe(0);
});
it('should not be rendered if there is only one commit', () => {
createLocalComponent({
mr: {
ffOnlyEnabled: true,
squash: true,
enableSquashBeforeMerge: true,
commitsCount: 1,
},
});
expect(findCommitEditElements().length).toBe(0);
});
it('should have one edit component if squash is enabled and there is more than 1 commit', () => {
createLocalComponent({
mr: {
ffOnlyEnabled: true,
squash: true,
enableSquashBeforeMerge: true,
commitsCount: 2,
},
});
expect(findCommitEditElements().length).toBe(1);
expect(findFirstCommitEditLabel()).toBe('Squash commit message');
});
});
it('should have one edit component when squash is disabled', () => { it('should have one edit component when squash is disabled', () => {
createLocalComponent(); createLocalComponent();
expect(findCommitEditElements().length).toBe(1); expect(findCommitEditElements().length).toBe(1);
}); });
const findFirstCommitEditLabel = () =>
findCommitEditElements()
.at(0)
.props('label');
it('should have two edit components when squash is enabled and there is more than 1 commit', () => { it('should have two edit components when squash is enabled and there is more than 1 commit', () => {
createLocalComponent({ createLocalComponent({
mr: { mr: {
......
...@@ -2773,7 +2773,7 @@ describe Ci::Build do ...@@ -2773,7 +2773,7 @@ describe Ci::Build do
end end
context 'when ref is merge request' do context 'when ref is merge request' do
let(:merge_request) { create(:merge_request, :with_merge_request_pipeline) } let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
let(:pipeline) { merge_request.merge_request_pipelines.first } let(:pipeline) { merge_request.merge_request_pipelines.first }
let(:build) { create(:ci_build, ref: merge_request.source_branch, tag: false, pipeline: pipeline, project: project) } let(:build) { create(:ci_build, ref: merge_request.source_branch, tag: false, pipeline: pipeline, project: project) }
...@@ -2831,7 +2831,7 @@ describe Ci::Build do ...@@ -2831,7 +2831,7 @@ describe Ci::Build do
end end
context 'when ref is merge request' do context 'when ref is merge request' do
let(:merge_request) { create(:merge_request, :with_merge_request_pipeline) } let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
let(:pipeline) { merge_request.merge_request_pipelines.first } let(:pipeline) { merge_request.merge_request_pipelines.first }
let(:build) { create(:ci_build, ref: merge_request.source_branch, tag: false, pipeline: pipeline, project: project) } let(:build) { create(:ci_build, ref: merge_request.source_branch, tag: false, pipeline: pipeline, project: project) }
......
...@@ -18,7 +18,7 @@ describe HasRef do ...@@ -18,7 +18,7 @@ describe HasRef do
end end
context 'when it was triggered by merge request' do context 'when it was triggered by merge request' do
let(:merge_request) { create(:merge_request, :with_merge_request_pipeline) } let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
let(:pipeline) { merge_request.merge_request_pipelines.first } let(:pipeline) { merge_request.merge_request_pipelines.first }
let(:build) { create(:ci_build, pipeline: pipeline) } let(:build) { create(:ci_build, pipeline: pipeline) }
...@@ -67,7 +67,7 @@ describe HasRef do ...@@ -67,7 +67,7 @@ describe HasRef do
end end
context 'when it is triggered by a merge request' do context 'when it is triggered by a merge request' do
let(:merge_request) { create(:merge_request, :with_merge_request_pipeline) } let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
let(:pipeline) { merge_request.merge_request_pipelines.first } let(:pipeline) { merge_request.merge_request_pipelines.first }
let(:build) { create(:ci_build, tag: false, pipeline: pipeline) } let(:build) { create(:ci_build, tag: false, pipeline: pipeline) }
......
...@@ -3,6 +3,7 @@ require 'spec_helper' ...@@ -3,6 +3,7 @@ require 'spec_helper'
describe PipelineEntity do describe PipelineEntity do
include Gitlab::Routing include Gitlab::Routing
set(:project) { create(:project) }
set(:user) { create(:user) } set(:user) { create(:user) }
set(:project) { create(:project) } set(:project) { create(:project) }
let(:request) { double('request') } let(:request) { double('request') }
...@@ -134,12 +135,12 @@ describe PipelineEntity do ...@@ -134,12 +135,12 @@ describe PipelineEntity do
end end
context 'when pipeline is detached merge request pipeline' do context 'when pipeline is detached merge request pipeline' do
let(:merge_request) { create(:merge_request, :with_merge_request_pipeline) } let(:merge_request) { create(:merge_request, :with_detached_merge_request_pipeline) }
let(:project) { merge_request.target_project } let(:project) { merge_request.target_project }
let(:pipeline) { merge_request.merge_request_pipelines.first } let(:pipeline) { merge_request.merge_request_pipelines.first }
it 'makes detached flag true' do it 'makes detached flag true' do
expect(subject[:flags][:detached]).to be_truthy expect(subject[:flags][:detached_merge_request_pipeline]).to be_truthy
end end
context 'when user is a developer' do context 'when user is a developer' do
...@@ -175,5 +176,19 @@ describe PipelineEntity do ...@@ -175,5 +176,19 @@ describe PipelineEntity do
end end
end end
end end
context 'when pipeline is merge request pipeline' do
let(:merge_request) { create(:merge_request, :with_merge_request_pipeline, merge_sha: 'abc') }
let(:project) { merge_request.target_project }
let(:pipeline) { merge_request.merge_request_pipelines.first }
it 'makes detached flag false' do
expect(subject[:flags][:detached_merge_request_pipeline]).to be_falsy
end
it 'makes atached flag true' do
expect(subject[:flags][:merge_request_pipeline]).to be_truthy
end
end
end end
end end
...@@ -102,7 +102,7 @@ describe PipelineSerializer do ...@@ -102,7 +102,7 @@ describe PipelineSerializer do
let!(:merge_request_1) do let!(:merge_request_1) do
create(:merge_request, create(:merge_request,
:with_merge_request_pipeline, :with_detached_merge_request_pipeline,
target_project: project, target_project: project,
target_branch: 'master', target_branch: 'master',
source_project: project, source_project: project,
...@@ -111,7 +111,7 @@ describe PipelineSerializer do ...@@ -111,7 +111,7 @@ describe PipelineSerializer do
let!(:merge_request_2) do let!(:merge_request_2) do
create(:merge_request, create(:merge_request,
:with_merge_request_pipeline, :with_detached_merge_request_pipeline,
target_project: project, target_project: project,
target_branch: 'master', target_branch: 'master',
source_project: project, source_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