summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Eastwood <contact@ericeastwood.com>2017-09-18 17:06:47 -0500
committerEric Eastwood <contact@ericeastwood.com>2017-09-19 23:48:40 -0500
commitf7f9847b26fd9f401039908843de2b660473e73d (patch)
treea66ffe98c8e912a426de98470205a885da7d113a
parentccdf687baa82dd0e0f809cfb24dc892db756bad7 (diff)
downloadgitlab-ce-f7f9847b26fd9f401039908843de2b660473e73d.tar.gz
Port fast-forward MR widget states from EE
See https://gitlab.com/gitlab-org/gitlab-ce/issues/20076
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js51
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js7
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js1
-rw-r--r--app/serializers/merge_request_entity.rb1
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js99
-rw-r--r--spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js80
7 files changed, 157 insertions, 83 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js
index 703f3a56a34..3cbcbdd52c5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.js
@@ -26,6 +26,7 @@ export default {
<ci-icon v-else :status="statusObj" />
<button
v-if="showDisabledButton"
+ ref="mergeButton"
type="button"
class="btn btn-success btn-sm"
disabled="true">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js
index f9cb79a0bc1..f2245a532f4 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.js
@@ -10,27 +10,40 @@ export default {
},
template: `
<div class="mr-widget-body media">
- <status-icon status="failed" showDisabledButton />
+ <status-icon
+ ref="statusIcon"
+ 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
+ <template v-if="mr.ffOnlyEnabled">
+ <span class="bold">
+ Fast-forward merge is not possible.
+ To merge this request, first rebase locally
</span>
- </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>
+ <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"
+ ref="resolveConflictsButton"
+ :href="mr.conflictResolutionPath"
+ class="btn btn-default btn-xs">
+ Resolve conflicts
+ </a>
+ <a
+ v-if="mr.canMerge"
+ ref="mergeLocallyButton"
+ class="btn btn-default btn-xs"
+ data-toggle="modal"
+ href="#modal_merge_info">
+ Merge locally
+ </a>
+ </template>
</div>
</div>
`,
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js
index ad709da51ee..e1c37add496 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js
@@ -284,7 +284,14 @@ export default {
:mr="mr"
:is-merge-button-disabled="isMergeButtonDisabled" />
+ <span
+ v-if="mr.ffOnlyEnabled"
+ ref="fastForwardMessage">
+ Fast-forward merge without a merge commit
+ </span>
<button
+ v-else
+ ref="modifyCommitMessageButton"
@click="toggleCommitMessageEditor"
:disabled="isMergeButtonDisabled"
class="btn btn-default btn-xs"
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
index 29464662578..03969e33e97 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js
@@ -57,6 +57,7 @@ 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.statusPath = data.status_path;
this.emailPatchesPath = data.email_patches_path;
this.plainDiffPath = data.plain_diff_path;
diff --git a/app/serializers/merge_request_entity.rb b/app/serializers/merge_request_entity.rb
index 1f5ce2ef58c..5f2700df692 100644
--- a/app/serializers/merge_request_entity.rb
+++ b/app/serializers/merge_request_entity.rb
@@ -17,7 +17,6 @@ class MergeRequestEntity < IssuableEntity
merge_request.project.merge_requests_ff_only_enabled
end
-
# Events
expose :merge_event, using: EventEntity
expose :closed_event, using: EventEntity
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
index 3b7b7d93662..d4b18703b25 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js
@@ -2,17 +2,16 @@ import Vue from 'vue';
import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts';
const path = '/conflicts';
-const createComponent = () => {
+const createComponent = (customConfig = {}) => {
const Component = Vue.extend(conflictsComponent);
+ const config = Object.assign({
+ mr: {},
+ }, customConfig);
+
return new Component({
el: document.createElement('div'),
- propsData: {
- mr: {
- canMerge: true,
- conflictResolutionPath: path,
- },
- },
+ propsData: config,
});
};
@@ -27,44 +26,78 @@ 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 = createComponent({
+ mr: {
+ canMerge: true,
+ conflictResolutionPath: path,
+ },
+ });
+ });
+
+ 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.$refs.resolveConflictsButton;
+
+ expect(resolveButton.textContent).toContain('Resolve conflicts');
+ expect(resolveButton.getAttribute('href')).toEqual(path);
+ });
+
+ it('should have merge buttons', () => {
+ const mergeButton = vm.$refs.statusIcon.$refs.mergeButton;
+ const mergeLocallyButton = vm.$refs.mergeLocallyButton;
+
+ expect(mergeButton.textContent).toContain('Merge');
+ expect(mergeButton.disabled).toBeTruthy();
+ expect(mergeButton.classList.contains('btn-success')).toBeTruthy();
+ 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 = createComponent({
+ mr: {
+ canMerge: false,
+ },
+ });
});
- it('should show proper message', (done) => {
- Vue.nextTick(() => {
- expect(vm.$el.textContent).toContain('ask someone with write access');
- done();
- });
+ it('should show proper message', () => {
+ expect(vm.$el.textContent).toContain('ask someone with write access');
+ });
+
+ it('should not have action buttons', () => {
+ expect(vm.$refs.statusIcon.$refs.mergeButton).toBeDefined();
+ expect(vm.$refs.resolveConflictsButton).toBeUndefined();
+ expect(vm.$refs.mergeLocallyButton).toBeUndefined();
});
+ });
+
+ describe('when fast-forward merge enabled', () => {
+ let vm;
- 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();
+ beforeEach(() => {
+ vm = createComponent({
+ mr: {
+ ffOnlyEnabled: true,
+ },
});
});
+
+ 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');
+ });
});
});
});
diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
index 03a52f1f91c..f36b74c9e94 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
@@ -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.$refs.fastForwardMessage).toBeUndefined();
+ expect(customVm.$refs.modifyCommitMessageButton).toBeDefined();
+ });
+
+ it('when fast-forward merge is enabled, only show fast-forward message', () => {
+ const customVm = createComponent({
+ mr: { ffOnlyEnabled: true },
+ });
+
+ expect(customVm.$refs.fastForwardMessage).toBeDefined();
+ expect(customVm.$refs.modifyCommitMessageButton).toBeUndefined();
+ });
+ });
});