Commit 20e2d7eb authored by Sean McGivern's avatar Sean McGivern

Merge branch 'move_ff_to_ce' into 'master'

Refactoring after moving fast-forward merge to CE

See merge request gitlab-org/gitlab-ee!2937
parents 253d7243 eb0ebb9a
......@@ -27,7 +27,7 @@ export default {
<button
v-if="showDisabledButton"
type="button"
class="btn btn-success btn-sm"
class="js-disabled-merge-button btn btn-success btn-sm"
disabled="true">
Merge
</button>
......
......@@ -10,27 +10,37 @@ export default {
},
template: `
<div class="mr-widget-body media">
<status-icon status="failed" showDisabledButton />
<status-icon
status="failed"
showDisabledButton />
<div class="media-body space-children">
<span class="bold">
There are merge conflicts<span v-if="!mr.canMerge">.</span>
<span v-if="!mr.canMerge">
Resolve these conflicts or ask someone with write access to this repository to merge it locally
</span>
<span
v-if="mr.shouldBeRebased"
class="bold">
Fast-forward merge is not possible.
To merge this request, first rebase locally.
</span>
<a
v-if="mr.canMerge && mr.conflictResolutionPath"
:href="mr.conflictResolutionPath"
class="btn btn-default btn-xs js-resolve-conflicts-button">
Resolve conflicts
</a>
<a
v-if="mr.canMerge"
class="btn btn-default btn-xs js-merge-locally-button"
data-toggle="modal"
href="#modal_merge_info">
Merge locally
</a>
<template v-else>
<span class="bold">
There are merge conflicts<span v-if="!mr.canMerge">.</span>
<span v-if="!mr.canMerge">
Resolve these conflicts or ask someone with write access to this repository to merge it locally
</span>
</span>
<a
v-if="mr.canMerge && mr.conflictResolutionPath"
:href="mr.conflictResolutionPath"
class="js-resolve-conflicts-button btn btn-default btn-xs">
Resolve conflicts
</a>
<a
v-if="mr.canMerge"
class="js-merge-locally-button btn btn-default btn-xs"
data-toggle="modal"
href="#modal_merge_info">
Merge locally
</a>
</template>
</div>
</div>
`,
......
......@@ -288,14 +288,16 @@ export default {
:mr="mr"
:is-merge-button-disabled="isMergeButtonDisabled" />
<span v-if="mr.ffOnlyEnabled">
<span
v-if="mr.ffOnlyEnabled"
class="js-fast-forward-message">
Fast-forward merge without a merge commit
</span>
<button
v-else
@click="toggleCommitMessageEditor"
:disabled="isMergeButtonDisabled"
class="btn btn-default btn-xs"
class="js-modify-commit-message-button btn btn-default btn-xs"
type="button">
Modify commit message
</button>
......
......@@ -59,6 +59,8 @@ export default class MergeRequestStore {
this.onlyAllowMergeIfPipelineSucceeds = data.only_allow_merge_if_pipeline_succeeds || false;
this.mergeWhenPipelineSucceeds = data.merge_when_pipeline_succeeds || false;
this.mergePath = data.merge_path;
this.ffOnlyEnabled = data.ff_only_enabled;
this.shouldBeRebased = !!data.should_be_rebased;
this.statusPath = data.status_path;
this.emailPatchesPath = data.email_patches_path;
this.plainDiffPath = data.plain_diff_path;
......
......@@ -347,6 +347,7 @@ class ProjectsController < Projects::ApplicationController
:tag_list,
:visibility_level,
:template_name,
:merge_method,
project_feature_attributes: %i[
builds_access_level
......
......@@ -12,7 +12,6 @@ class License < ActiveRecord::Base
contribution_analytics
elastic_search
export_issues
fast_forward_merge
group_webhooks
issuable_default_templates
issue_board_focus_mode
......@@ -63,7 +62,6 @@ class License < ActiveRecord::Base
cross_project_pipelines
deploy_board
export_issues
fast_forward_merge
file_locks
group_webhooks
issuable_default_templates
......
......@@ -549,6 +549,14 @@ class MergeRequest < ActiveRecord::Base
true
end
def ff_merge_possible?
project.repository.ancestor?(target_branch_sha, diff_head_sha)
end
def should_be_rebased?
project.ff_merge_must_be_possible? && !ff_merge_possible?
end
def can_cancel_merge_when_pipeline_succeeds?(current_user)
can_be_merged_by?(current_user) || self.author == current_user
end
......
......@@ -1586,6 +1586,34 @@ class Project < ActiveRecord::Base
Gitlab::GlRepository.gl_repository(self, is_wiki)
end
def merge_method
if self.merge_requests_ff_only_enabled
:ff
elsif self.merge_requests_rebase_enabled
:rebase_merge
else
:merge
end
end
def merge_method=(method)
case method.to_s
when "ff"
self.merge_requests_ff_only_enabled = true
self.merge_requests_rebase_enabled = true
when "rebase_merge"
self.merge_requests_ff_only_enabled = false
self.merge_requests_rebase_enabled = true
when "merge"
self.merge_requests_ff_only_enabled = false
self.merge_requests_rebase_enabled = false
end
end
def ff_merge_must_be_possible?
self.merge_requests_ff_only_enabled || self.merge_requests_rebase_enabled
end
private
def storage
......
- form = local_assigns.fetch(:form)
- project = local_assigns.fetch(:project)
.radio
= label_tag :project_merge_method_ff do
= form.radio_button :merge_method, :ff, class: "js-merge-method-radio"
%strong Fast-forward merge
%br
%span.descr
No merge commits are created and all merges are fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.
%br
%span.descr
When fast-forward merge is not possible, the user must first rebase locally.
- form = local_assigns.fetch(:form)
.radio
= label_tag :project_merge_method_rebase_merge do
= form.radio_button :merge_method, :rebase_merge, class: "js-merge-method-radio"
%strong Merge commit with semi-linear history
%br
%span.descr
A merge commit is created for every merge, but merging is only allowed if fast-forward merge is possible.
This way you could make sure that if this merge request would build, after merging to target branch it would also build.
%br
%span.descr
When fast-forward merge is not possible, the user must first rebase locally.
- form = local_assigns.fetch(:form)
= render 'projects/ee/merge_request_settings', form: form, project: @project
.form-group
= label_tag :merge_method_merge, class: 'label-light' do
Merge method
.radio
= label_tag :project_merge_method_merge do
= form.radio_button :merge_method, :merge, class: "js-merge-method-radio"
%strong Merge commit
%br
%span.descr
A merge commit is created for every merge, and merging is allowed as long as there are no conflicts.
= render 'merge_request_rebase_settings', form: form
= render 'merge_request_fast_forward_settings', project: @project, form: form
= render 'projects/merge_request_merge_settings', form: form
......@@ -95,7 +95,7 @@
= render 'shared/promotions/promote_mr_features'
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "merge-request-settings-form" }, authenticity_token: true do |f|
= render 'merge_request_settings', form: f
= render 'projects/ee/merge_request_settings', form: f
= f.submit 'Save changes', class: "btn btn-save"
= render 'projects/ee/service_desk_settings'
......
# Fast-forward merge requests
> Included in [GitLab Enterprise Edition Starter][products].
Retain a linear Git history and a way to accept merge requests without
creating merge commits.
......
......@@ -23,15 +23,15 @@ With GitLab merge requests, you can:
- Organize your issues and merge requests consistently throughout the project with [labels](../../project/labels.md)
- Add a time estimation and the time spent with that merge request with [Time Tracking](../../../workflow/time_tracking.html#time-tracking)
- [Resolve merge conflicts from the UI](#resolve-conflicts)
- Enable [fast-forward merge requests](#fast-forward-merge-requests)
- Enable [semi-linear history merge requests](#semi-linear-history-merge-requests) as another security layer to guarantee the pipeline is passing in the target branch
With **[GitLab Enterprise Edition][ee]**, you can also:
- View the deployment process across projects with [Multi-Project Pipeline Graphs](../../../ci/multi_project_pipeline_graphs.md) (available only in GitLab Enterprise Edition Premium)
- Request [approvals](#merge-request-approvals) from your managers (available in GitLab Enterprise Edition Starter)
- Enable [fast-forward merge requests](#fast-forward-merge-requests) (available in GitLab Enterprise Edition Starter)
- [Squash and merge](#squash-and-merge) for a cleaner commit history (available in GitLab Enterprise Edition Starter)
- Enable [semi-linear history merge requests](#semi-linear-history-merge-requests) as another security layer to guarantee the pipeline is passing in the target branch (available in GitLab Enterprise Edition Starter)
- Analyze the impact of your changes with [Code Quality reports](#code-quality-reports) (available in GitLab Enterprise Edition Starter)
## Use cases
......@@ -145,6 +145,13 @@ have been marked as a **Work In Progress**.
[Learn more about settings a merge request as "Work In Progress".](work_in_progress_merge_requests.md)
## Fast-forward merge requests
If you prefer a linear Git history and a way to accept merge requests without
creating merge commits, you can configure this on a per-project basis.
[Read more about fast-forward merge requests.](fast_forward_merge.md)
## Merge request approvals
> Included in [GitLab Enterprise Edition Starter][products].
......@@ -158,8 +165,6 @@ list of approvers that will need to approve every merge request in a project.
## Semi-linear history merge requests
> Included in [GitLab Enterprise Edition Starter][products].
A merge commit is created for every merge, but the branch is only merged if
a fast-forward merge is possible. This ensures that if the merge request build
succeeded, the target branch build will also succeed after merging.
......@@ -167,15 +172,6 @@ succeeded, the target branch build will also succeed after merging.
Navigate to a project's settings, select the **Merge commit with semi-linear
history** option under **Merge Requests: Merge method** and save your changes.
## Fast-forward merge requests
> Included in [GitLab Enterprise Edition Starter][products].
If you prefer a linear Git history and a way to accept merge requests without
creating merge commits, you can configure this on a per-project basis.
[Read more about fast-forward merge requests.](fast_forward_merge.md)
## Code Quality reports
> Introduced in [GitLab Enterprise Edition Starter][products] 9.3.
......
......@@ -23,7 +23,7 @@ Add an [issue description template](../description_templates.md#description-temp
Set up your project's merge request settings:
- Set up the merge request method (merge commit, [fast-forward merge](https://docs.gitlab.com/ee/user/project/merge_requests/fast_forward_merge.html#fast-forward-merge-requests)). _Fast-forward is available in [GitLab Enterprise Edition Starter](https://about.gitlab.com/gitlab-ee/)._
- Set up the merge request method (merge commit, [fast-forward merge](../merge_requests/fast_forward_merge.html)).
- Merge request [description templates](../description_templates.md#description-templates).
- Enable [merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html#merge-request-approvals), _available in [GitLab Enterprise Edition Starter](https://about.gitlab.com/gitlab-ee/)_.
- Enable [merge only of pipeline succeeds](../merge_requests/merge_when_pipeline_succeeds.md).
......
......@@ -39,8 +39,8 @@
- [Revert changes in the UI](../user/project/merge_requests/revert_changes.md)
- [Merge requests versions](../user/project/merge_requests/versions.md)
- ["Work In Progress" merge requests](../user/project/merge_requests/work_in_progress_merge_requests.md)
- [Fast-forward merge requests](../user/project/merge_requests/fast_forward_merge.md)
- (EE) [Merge request approvals](../user/project/merge_requests/merge_request_approvals.md)
- (EE) [Fast-forward merge requests](../user/project/merge_requests/fast_forward_merge.md)
- (EE) [Repository mirroring](repository_mirroring.md)
- (EE Premium) [Service Desk](../user/project/service_desk.md)
- [Manage large binaries with Git LFS](lfs/manage_large_binaries_with_git_lfs.md)
......
......@@ -186,7 +186,7 @@ If you have an issue that spans across multiple repositories, the best thing is
![Vim screen showing the rebase view](rebase.png)
With git you can use an interactive rebase (`rebase -i`) to squash multiple commits into one and reorder them.
In GitLab Enterprise Edition Starter and GitLab.com, you can also [rebase before merge](../user/project/merge_requests/fast_forward_merge.md) from the web interface.
You can also [rebase before merge](../user/project/merge_requests/fast_forward_merge.md) from the web interface.
This functionality is useful if you made a couple of commits for small changes during development and want to replace them with a single commit or if you want to make the order more logical.
However you should never rebase commits you have pushed to a remote server.
Somebody can have referred to the commits or cherry-picked them.
......@@ -247,7 +247,7 @@ Before accepting a merge request, select `rebase before merge`.
![Merge request widget](merge_request_widget.png)
GitLab will attempt to cleanly rebase before merging branches. If clean rebase is not possible, regular merge will be performed.
If clean rebase is possible and history of the traget branch will be altered with the the merge.
If clean rebase is possible and history of the target branch will be altered with the the merge.
In conclusion, we can say that you should try to prevent merge commits, but not eliminate them.
Your codebase should be clean but your history should represent what actually happened.
......
......@@ -79,7 +79,7 @@ export default {
Fast-forward merge is not possible.
Rebase the source branch onto
<span class="label-branch">{{mr.targetBranch}}</span>
to allow this merge request to be merged
to allow this merge request to be merged.
</span>
</template>
<template v-if="!mr.rebaseInProgress && mr.canPushToSourceBranch && !isMakingRequest">
......@@ -97,7 +97,7 @@ export default {
<span class="bold">
Fast-forward merge is not possible.
Rebase the source branch onto the target branch or merge target
branch into source branch to allow this merge request to be merged
branch into source branch to allow this merge request to be merged.
</span>
</div>
</template>
......
......@@ -23,12 +23,10 @@ export default class MergeRequestStore extends CEMergeRequestStore {
}
initRebase(data) {
this.shouldBeRebased = !!data.should_be_rebased;
this.canPushToSourceBranch = data.can_push_to_source_branch;
this.rebaseInProgress = data.rebase_in_progress;
this.approvalsLeft = !data.approved;
this.rebasePath = data.rebase_path;
this.ffOnlyEnabled = data.ff_only_enabled;
}
initGeo(data) {
......
......@@ -12,7 +12,6 @@ module EE
approver_group_ids
approver_ids
issues_template
merge_method
merge_requests_template
disable_overriding_approvers_per_merge_request
repository_size_limit
......
......@@ -13,16 +13,6 @@ module EE
delegate :codeclimate_artifact, to: :base_pipeline, prefix: :base, allow_nil: true
end
def ff_merge_possible?
project.repository.ancestor?(target_branch_sha, diff_head_sha)
end
def should_be_rebased?
project.feature_available?(:merge_request_rebase) &&
project.ff_merge_must_be_possible? &&
!ff_merge_possible?
end
def rebase_dir_path
File.join(::Gitlab.config.shared.path, 'tmp/rebase', source_project.id.to_s, id.to_s).to_s
end
......
......@@ -337,34 +337,6 @@ module EE
@path_lock_finder.find(path, exact_match: exact_match, downstream: downstream)
end
def merge_method
if self.merge_requests_ff_only_enabled
:ff
elsif self.merge_requests_rebase_enabled
:rebase_merge
else
:merge
end
end
def merge_method=(method)
case method.to_s
when "ff"
self.merge_requests_ff_only_enabled = true
self.merge_requests_rebase_enabled = true
when "rebase_merge"
self.merge_requests_ff_only_enabled = false
self.merge_requests_rebase_enabled = true
when "merge"
self.merge_requests_ff_only_enabled = false
self.merge_requests_rebase_enabled = false
end
end
def ff_merge_must_be_possible?
self.merge_requests_ff_only_enabled || self.merge_requests_rebase_enabled
end
def import_url_updated?
# check if import_url has been updated and it's not just the first assignment
import_url_changed? && changes['import_url'].first
......@@ -458,7 +430,7 @@ module EE
alias_method :merge_requests_rebase_enabled?, :merge_requests_rebase_enabled
def merge_requests_ff_only_enabled
super && feature_available?(:fast_forward_merge)
super
end
alias_method :merge_requests_ff_only_enabled?, :merge_requests_ff_only_enabled
......
- form = local_assigns.fetch(:form)
- project = local_assigns.fetch(:project)
.radio
= label_tag :project_merge_method_ff do
= form.radio_button :merge_method, :ff, class: "js-merge-method-radio"
%strong Fast-forward merge
%br
%span.descr
No merge commits are created and all merges are fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.
- if project.feature_available?(:merge_request_rebase)
%br
%span.descr
When fast-forward merge is not possible, the user is given the option to rebase.
- form = local_assigns.fetch(:form)
.radio
= label_tag :project_merge_method_rebase_merge do
= form.radio_button :merge_method, :rebase_merge, class: "js-merge-method-radio"
%strong Merge commit with semi-linear history
%br
%span.descr
A merge commit is created for every merge, but merging is only allowed if fast-forward merge is possible.
This way you could make sure that if this merge request would build, after merging to target branch it would also build.
%br
%span.descr
When fast-forward merge is not possible, the user is given the option to rebase.
- form = local_assigns.fetch(:form)
- project = local_assigns.fetch(:project)
- if project.feature_available?(:merge_request_rebase) || project.feature_available?(:fast_forward_merge)
.form-group
= label_tag :merge_method_merge, class: 'label-light' do
Merge method
.radio
= label_tag :project_merge_method_merge do
= form.radio_button :merge_method, :merge, class: "js-merge-method-radio"
%strong Merge commit
%br
%span.descr
A merge commit is created for every merge, and merging is allowed as long as there are no conflicts.
.form-group
= label_tag :merge_method_merge, class: 'label-light' do
Merge method
.radio
= label_tag :project_merge_method_merge do
= form.radio_button :merge_method, :merge, class: "js-merge-method-radio"
%strong Merge commit
%br
%span.descr
A merge commit is created for every merge, and merging is allowed as long as there are no conflicts.
= render 'projects/ee/merge_request_rebase_settings', form: form
- if project.feature_available?(:merge_request_rebase)
.radio
= label_tag :project_merge_method_rebase_merge do
= form.radio_button :merge_method, :rebase_merge, class: "js-merge-method-radio"
%strong Merge commit with semi-linear history
%br
%span.descr
A merge commit is created for every merge, but merging is only allowed if fast-forward merge is possible.
This way you could make sure that if this merge request would build, after merging to target branch it would also build.
%br
%span.descr
When fast-forward merge is not possible, the user is given the option to rebase.
= render 'projects/ee/merge_request_fast_forward_settings', project: @project, form: form
- if project.feature_available?(:fast_forward_merge)
.radio
= label_tag :project_merge_method_ff do
= form.radio_button :merge_method, :ff, class: "js-merge-method-radio"
%strong Fast-forward merge
%br
%span.descr
No merge commits are created and all merges are fast-forwarded, which means that merging is only allowed if the branch could be fast-forwarded.
- if project.feature_available?(:merge_request_rebase)
%br
%span.descr
When fast-forward merge is not possible, the user is given the option to rebase.
- if @project.feature_available?(:issuable_default_templates)
.form-group
......@@ -48,4 +25,6 @@
.hint
Description parsed with #{link_to "GitLab Flavored Markdown", help_page_path('user/markdown'), target: '_blank'}.
= render 'projects/ee/merge_request_approvals_settings', project: project, form: form
= render 'projects/ee/merge_request_approvals_settings', project: @project, form: form
= render 'projects/merge_request_merge_settings', form: form
- if show_promotions? && show_callout?('promote_mr_features_dismissed') && (!@project.feature_available?(:merge_request_approvers) || !@project.feature_available?(:fast_forward_merge))
- if show_promotions? && show_callout?('promote_mr_features_dismissed') && !@project.feature_available?(:merge_request_approvers)
.user-callout.promotion-callout.append-bottom-20.js-mr-approval-callout#promote_mr_features{ data: { uid: 'promote_mr_features_dismissed' } }
.bordered-box.content-block
%button.btn.btn-default.close.js-close-callout{ type: 'button', 'aria-label' => 'Dismiss Merge Request promotion' }
......@@ -15,10 +15,5 @@
= link_to 'Merge Request Approvals', help_page_path('user/project/merge_requests/merge_request_approvals.html'), target: '_blank'
%p
Merge request approvals allow you to set the number of necessary approvals and predefine a list of approvers that will need to approve every merge request in a project.
- unless @project.feature_available?(:fast_forward_merge)
%li
= link_to 'Fast-forward Merge', help_page_path('user/project/merge_requests/fast_forward_merge.html'), target: '_blank'
%p
If you prefer a linear Git history and a way to accept merge requests without creating merge commits, you can configure this on a per-project basis.
= render 'shared/promotions/promotion_link_project'
......@@ -312,6 +312,24 @@ describe ProjectsController do
end
end
it 'updates Fast Forward Merge attributes' do
controller.instance_variable_set(:@project, project)
params = {
merge_method: :ff
}
put :update,
namespace_id: project.namespace,
id: project.id,
project: params
expect(response).to have_http_status(302)
params.each do |param, value|
expect(project.public_send(param)).to eq(value)
end
end
def update_project(**parameters)
put :update,
namespace_id: project.namespace.path,
......
......@@ -109,38 +109,6 @@ describe ProjectsController do
end
end
it 'updates Fast Forward Merge attributes' do
params = {
merge_method: :ff
}
put :update,
namespace_id: project.namespace,
id: project.id,
project: params
expect(response).to have_http_status(302)
params.each do |param, value|
expect(project.public_send(param)).to eq(value)
end
end
it 'updates Fast Forward Merge attributes' do
params = {
merge_method: :ff
}
put :update,
namespace_id: project.namespace,
id: project.id,
project: params
expect(response).to have_http_status(302)
params.each do |param, value|
expect(project.public_send(param)).to eq(value)
end
end
it 'updates Service Desk attributes' do
allow(Gitlab::IncomingEmail).to receive(:enabled?) { true }
allow(Gitlab::IncomingEmail).to receive(:supports_wildcard?) { true }
......
......@@ -723,23 +723,15 @@ describe Project do
end
describe '#merge_method' do
where(:ff, :rebase, :ff_licensed, :rebase_licensed, :method) do
true | true | true | true | :ff
true | true | true | false | :ff
true | true | false | true | :rebase_merge
true | true | false | false | :merge
true | false | true | true | :ff
true | false | true | false | :ff
true | false | false | true | :merge
true | false | false | false | :merge
false | true | true | true | :rebase_merge
false | true | true | false | :merge
false | true | false | true | :rebase_merge
false | true | false | false | :merge
false | false | true | true | :merge
false | false | true | false | :merge
false | false | false | true | :merge
false | false | false | false | :merge
where(:ff, :rebase, :rebase_licensed, :method) do
true | true | true | :ff
true | true | false | :ff
true | false | true | :ff
true | false | false | :ff
false | true | true | :rebase_merge
false | true | false | :merge
false | false | true | :merge
false | false | false | :merge
end
with_them do
......@@ -748,7 +740,7 @@ describe Project do
subject { project.merge_method }
before do
stub_licensed_features(merge_request_rebase: rebase_licensed, fast_forward_merge: ff_licensed)
stub_licensed_features(merge_request_rebase: rebase_licensed)
end
it { is_expected.to eq(method) }
......
......@@ -202,14 +202,13 @@ describe 'Merge request', :js do
end
end
context 'view merge request with MWPS enabled but fast-forward merge is not possible' do
context 'view merge request where fast-forward merge is not possible' do
before do
project.update(merge_requests_ff_only_enabled: true)
merge_request.update(
merge_when_pipeline_succeeds: true,
merge_user: merge_request.author,
state: :can_be_merged
merge_status: :cannot_be_merged
)
visit project_merge_request_path(project, merge_request)
......
......@@ -32,6 +32,32 @@ describe 'Edit Project Settings' do
end
end
describe 'Merge request settings section' do
it 'shows "Merge commit" strategy' do
visit edit_project_path(project)
page.within '.merge-requests-feature' do
expect(page).to have_content 'Merge commit'
end
end
it 'shows "Merge commit with semi-linear history " strategy' do
visit edit_project_path(project)
page.within '.merge-requests-feature' do
expect(page).to have_content 'Merge commit with semi-linear history'
end
end
it 'shows "Fast-forward merge" strategy' do
visit edit_project_path(project)
page.within '.merge-requests-feature' do
expect(page).to have_content 'Fast-forward merge'
end
end
end
describe 'Rename repository section' do
context 'with invalid characters' do
it 'shows errors for invalid project path/name' do
......
import Vue from 'vue';
import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts';
import mountComponent from '../../../helpers/vue_mount_component_helper';
const ConflictsComponent = Vue.extend(conflictsComponent);
const path = '/conflicts';
const createComponent = () => {
const Component = Vue.extend(conflictsComponent);
return new Component({
el: document.createElement('div'),
propsData: {
mr: {
canMerge: true,
conflictResolutionPath: path,
},
},
});
};
describe('MRWidgetConflicts', () => {
describe('props', () => {
......@@ -27,44 +16,90 @@ describe('MRWidgetConflicts', () => {
});
describe('template', () => {
it('should have correct elements', () => {
const el = createComponent().$el;
const resolveButton = el.querySelector('.js-resolve-conflicts-button');
const mergeButton = el.querySelector('.mr-widget-body .btn');
const mergeLocallyButton = el.querySelector('.js-merge-locally-button');
expect(el.textContent).toContain('There are merge conflicts');
expect(el.textContent).not.toContain('ask someone with write access');
expect(el.querySelector('.btn-success').disabled).toBeTruthy();
expect(resolveButton.textContent).toContain('Resolve conflicts');
expect(resolveButton.getAttribute('href')).toEqual(path);
expect(mergeButton.textContent).toContain('Merge');
expect(mergeLocallyButton.textContent).toContain('Merge locally');
describe('when allowed to merge', () => {
let vm;
beforeEach(() => {
vm = mountComponent(ConflictsComponent, {
mr: {
canMerge: true,
conflictResolutionPath: path,
},
});
});
afterEach(() => {
vm.$destroy();
});
it('should tell you about conflicts without bothering other people', () => {
expect(vm.$el.textContent).toContain('There are merge conflicts');
expect(vm.$el.textContent).not.toContain('ask someone with write access');
});
it('should allow you to resolve the conflicts', () => {
const resolveButton = vm.$el.querySelector('.js-resolve-conflicts-button');
expect(resolveButton.textContent).toContain('Resolve conflicts');
expect(resolveButton.getAttribute('href')).toEqual(path);
});
it('should have merge buttons', () => {
const mergeButton = vm.$el.querySelector('.js-disabled-merge-button');
const mergeLocallyButton = vm.$el.querySelector('.js-merge-locally-button');
expect(mergeButton.textContent).toContain('Merge');
expect(mergeButton.disabled).toBeTruthy();
expect(mergeButton.classList.contains('btn-success')).toEqual(true);
expect(mergeLocallyButton.textContent).toContain('Merge locally');
});
});
describe('when user does not have permission to merge', () => {
let vm;
beforeEach(() => {
vm = createComponent();
vm.mr.canMerge = false;
vm = mountComponent(ConflictsComponent, {
mr: {
canMerge: false,
},
});
});
it('should show proper message', (done) => {
Vue.nextTick(() => {
expect(vm.$el.textContent).toContain('ask someone with write access');
done();
});
afterEach(() => {
vm.$destroy();
});
it('should show proper message', () => {
expect(vm.$el.textContent).toContain('ask someone with write access');
});
it('should not have action buttons', () => {
expect(vm.$el.querySelector('.js-disabled-merge-button')).toBeDefined();
expect(vm.$el.querySelector('.js-resolve-conflicts-button')).toBeNull();
expect(vm.$el.querySelector('.js-merge-locally-button')).toBeNull();
});
});
it('should not have action buttons', (done) => {
Vue.nextTick(() => {
expect(vm.$el.querySelectorAll('.btn').length).toBe(1);
expect(vm.$el.querySelector('.js-resolve-conflicts-button')).toEqual(null);
expect(vm.$el.querySelector('.js-merge-locally-button')).toEqual(null);
done();
describe('when fast-forward or semi-linear merge enabled', () => {
let vm;
beforeEach(() => {
vm = mountComponent(ConflictsComponent, {
mr: {
shouldBeRebased: true,
},
});
});
afterEach(() => {
vm.$destroy();
});
it('should tell you to rebase locally', () => {
expect(vm.$el.textContent).toContain('Fast-forward merge is not possible.');
expect(vm.$el.textContent).toContain('To merge this request, first rebase locally');
});
});
});
});
......@@ -182,36 +182,6 @@ describe('MRWidgetReadyToMerge', () => {
expect(vm.isMergeButtonDisabled).toBeTruthy();
});
});
describe('Remove source branch checkbox', () => {
describe('when user can merge but cannot delete branch', () => {
it('isRemoveSourceBranchButtonDisabled should be true', () => {
expect(vm.isRemoveSourceBranchButtonDisabled).toBe(true);
});
it('should be disabled in the rendered output', () => {
const checkboxElement = vm.$el.querySelector('#remove-source-branch-input');
expect(checkboxElement.getAttribute('disabled')).toBe('disabled');
});
});
describe('when user can merge and can delete branch', () => {
beforeEach(() => {
this.customVm = createComponent({
mr: { canRemoveSourceBranch: true },
});
});
it('isRemoveSourceBranchButtonDisabled should be false', () => {
expect(this.customVm.isRemoveSourceBranchButtonDisabled).toBe(false);
});
it('should be enabled in rendered output', () => {
const checkboxElement = this.customVm.$el.querySelector('#remove-source-branch-input');
expect(checkboxElement.getAttribute('disabled')).toBeNull();
});
});
});
});
describe('methods', () => {
......@@ -467,4 +437,54 @@ describe('MRWidgetReadyToMerge', () => {
});
});
});
describe('Remove source branch checkbox', () => {
describe('when user can merge but cannot delete branch', () => {
it('isRemoveSourceBranchButtonDisabled should be true', () => {
expect(vm.isRemoveSourceBranchButtonDisabled).toBe(true);
});
it('should be disabled in the rendered output', () => {
const checkboxElement = vm.$el.querySelector('#remove-source-branch-input');
expect(checkboxElement.getAttribute('disabled')).toBe('disabled');
});
});
describe('when user can merge and can delete branch', () => {
beforeEach(() => {
this.customVm = createComponent({
mr: { canRemoveSourceBranch: true },
});
});
it('isRemoveSourceBranchButtonDisabled should be false', () => {
expect(this.customVm.isRemoveSourceBranchButtonDisabled).toBe(false);
});
it('should be enabled in rendered output', () => {
const checkboxElement = this.customVm.$el.querySelector('#remove-source-branch-input');
expect(checkboxElement.getAttribute('disabled')).toBeNull();
});
});
});
describe('Commit message area', () => {
it('when using merge commits, should show "Modify commit message" button', () => {
const customVm = createComponent({
mr: { ffOnlyEnabled: false },
});
expect(customVm.$el.querySelector('.js-fast-forward-message')).toBeNull();
expect(customVm.$el.querySelector('.js-modify-commit-message-button')).toBeDefined();
});
it('when fast-forward merge is enabled, only show fast-forward message', () => {
const customVm = createComponent({
mr: { ffOnlyEnabled: true },
});
expect(customVm.$el.querySelector('.js-fast-forward-message')).toBeDefined();
expect(customVm.$el.querySelector('.js-modify-commit-message-button')).toBeNull();
});
});
});
......@@ -48,10 +48,11 @@ describe MergeRequestEntity do
:create_issue_to_resolve_discussions_path,
:source_branch_path, :target_branch_commits_path,
:target_branch_tree_path, :commits_count, :merge_ongoing,
:ff_only_enabled,
## EE
:can_push_to_source_branch, :approvals_before_merge,
:squash, :rebase_commit_sha, :rebase_in_progress,
:approvals_path, :ff_only_enabled)
:approvals_path)
end
it 'has email_patches_path' do
......
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