Commit 9a18d3af authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'ph/344663/mergeButtonFlash' into 'master'

Fixes merge button flashing active state

See merge request gitlab-org/gitlab!79967
parents 4cb46fff 22ad4165
<script>
import { MERGE_ACTIVE_STATUS_PHRASES } from '../../constants';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import simplePoll from '~/lib/utils/simple_poll';
import MergeRequest from '../../../merge_request';
import eventHub from '../../event_hub';
import { MERGE_ACTIVE_STATUS_PHRASES, STATE_MACHINE } from '../../constants';
import statusIcon from '../mr_widget_status_icon.vue';
const { transitions } = STATE_MACHINE;
const { MERGE_FAILURE } = transitions;
export default {
name: 'MRWidgetMerging',
components: {
......@@ -12,6 +19,10 @@ export default {
type: Object,
required: true,
},
service: {
type: Object,
required: true,
},
},
data() {
const statusCount = MERGE_ACTIVE_STATUS_PHRASES.length;
......@@ -20,6 +31,53 @@ export default {
mergeStatus: MERGE_ACTIVE_STATUS_PHRASES[Math.floor(Math.random() * statusCount)],
};
},
mounted() {
this.initiateMergePolling();
},
methods: {
initiateMergePolling() {
simplePoll(
(continuePolling, stopPolling) => {
this.handleMergePolling(continuePolling, stopPolling);
},
{ timeout: 0 },
);
},
handleMergePolling(continuePolling, stopPolling) {
this.service
.poll()
.then((res) => res.data)
.then((data) => {
if (data.state === 'merged') {
// If state is merged we should update the widget and stop the polling
eventHub.$emit('MRWidgetUpdateRequested');
eventHub.$emit('FetchActionsContent');
MergeRequest.hideCloseButton();
MergeRequest.decreaseCounter();
stopPolling();
refreshUserMergeRequestCounts();
// If user checked remove source branch and we didn't remove the branch yet
// we should start another polling for source branch remove process
if (this.removeSourceBranch && data.source_branch_exists) {
this.initiateRemoveSourceBranchPolling();
}
} else if (data.merge_error) {
eventHub.$emit('FailedToMerge', data.merge_error);
this.mr.transitionStateMachine({ transition: MERGE_FAILURE });
stopPolling();
} else {
// MR is not merged yet, continue polling until the state becomes 'merged'
continuePolling();
}
})
.catch(() => {
this.mr.transitionStateMachine({ transition: MERGE_FAILURE });
stopPolling();
});
},
},
};
</script>
<template>
......
......@@ -14,7 +14,6 @@ import {
import { isEmpty } from 'lodash';
import readyToMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/ready_to_merge';
import readyToMergeQuery from 'ee_else_ce/vue_merge_request_widget/queries/states/ready_to_merge.query.graphql';
import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests';
import createFlash from '~/flash';
import { secondsToMilliseconds } from '~/lib/utils/datetime_utility';
import simplePoll from '~/lib/utils/simple_poll';
......@@ -22,7 +21,6 @@ import { __, s__ } from '~/locale';
import SmartInterval from '~/smart_interval';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { helpPagePath } from '~/helpers/help_page_helper';
import MergeRequest from '../../../merge_request';
import {
AUTO_MERGE_STRATEGIES,
WARNING,
......@@ -51,7 +49,7 @@ const MERGE_SUCCESS_STATUS = 'success';
const MERGE_HOOK_VALIDATION_ERROR_STATUS = 'hook_validation_error';
const { transitions } = STATE_MACHINE;
const { MERGE, MERGED, MERGE_FAILURE, AUTO_MERGE } = transitions;
const { MERGE, MERGE_FAILURE, AUTO_MERGE, MERGING } = transitions;
export default {
name: 'ReadyToMerge',
......@@ -412,7 +410,7 @@ export default {
eventHub.$emit('MRWidgetUpdateRequested');
this.mr.transitionStateMachine({ transition: AUTO_MERGE });
} else if (data.status === MERGE_SUCCESS_STATUS) {
this.initiateMergePolling();
this.mr.transitionStateMachine({ transition: MERGING });
} else if (hasError) {
eventHub.$emit('FailedToMerge', data.merge_error);
this.mr.transitionStateMachine({ transition: MERGE_FAILURE });
......@@ -443,52 +441,6 @@ export default {
onMergeWithFailedPipelineConfirmation() {
this.handleMergeButtonClick(false, true, true);
},
initiateMergePolling() {
simplePoll(
(continuePolling, stopPolling) => {
this.handleMergePolling(continuePolling, stopPolling);
},
{ timeout: 0 },
);
},
handleMergePolling(continuePolling, stopPolling) {
this.service
.poll()
.then((res) => res.data)
.then((data) => {
if (data.state === 'merged') {
// If state is merged we should update the widget and stop the polling
eventHub.$emit('MRWidgetUpdateRequested');
eventHub.$emit('FetchActionsContent');
MergeRequest.hideCloseButton();
MergeRequest.decreaseCounter();
this.mr.transitionStateMachine({ transition: MERGED });
stopPolling();
refreshUserMergeRequestCounts();
// If user checked remove source branch and we didn't remove the branch yet
// we should start another polling for source branch remove process
if (this.removeSourceBranch && data.source_branch_exists) {
this.initiateRemoveSourceBranchPolling();
}
} else if (data.merge_error) {
eventHub.$emit('FailedToMerge', data.merge_error);
this.mr.transitionStateMachine({ transition: MERGE_FAILURE });
stopPolling();
} else {
// MR is not merged yet, continue polling until the state becomes 'merged'
continuePolling();
}
})
.catch(() => {
createFlash({
message: __('Something went wrong while merging this merge request. Please try again.'),
});
this.mr.transitionStateMachine({ transition: MERGE_FAILURE });
stopPolling();
});
},
initiateRemoveSourceBranchPolling() {
// We need to show source branch is being removed spinner in another component
eventHub.$emit('SetBranchRemoveFlag', [true]);
......
......@@ -68,6 +68,7 @@ const STATE_MACHINE = {
states: {
IDLE: 'IDLE',
MERGING: 'MERGING',
MERGED: 'MERGED',
AUTO_MERGE: 'AUTO_MERGE',
},
transitions: {
......@@ -75,6 +76,7 @@ const STATE_MACHINE = {
AUTO_MERGE: 'start-auto-merge',
MERGE_FAILURE: 'merge-failed',
MERGED: 'merge-done',
MERGING: 'merging',
},
};
const { states, transitions } = STATE_MACHINE;
......@@ -86,11 +88,12 @@ STATE_MACHINE.definition = {
on: {
[transitions.MERGE]: states.MERGING,
[transitions.AUTO_MERGE]: states.AUTO_MERGE,
[transitions.MERGING]: states.MERGING,
},
},
[states.MERGING]: {
on: {
[transitions.MERGED]: states.IDLE,
[transitions.MERGED]: states.MERGED,
[transitions.MERGE_FAILURE]: states.IDLE,
},
},
......@@ -110,6 +113,7 @@ export const stateToTransitionMap = {
};
export const stateToComponentMap = {
[states.MERGING]: classStateMap[stateKey.merging],
[states.MERGED]: classStateMap[stateKey.merged],
[states.AUTO_MERGE]: classStateMap[stateKey.autoMergeEnabled],
};
......
......@@ -33905,9 +33905,6 @@ msgstr ""
msgid "Something went wrong while inserting your image. Please try again."
msgstr ""
msgid "Something went wrong while merging this merge request. Please try again."
msgstr ""
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
......
import { shallowMount } from '@vue/test-utils';
import simplePoll from '~/lib/utils/simple_poll';
import MrWidgetMerging from '~/vue_merge_request_widget/components/states/mr_widget_merging.vue';
jest.mock('~/lib/utils/simple_poll', () =>
jest.fn().mockImplementation(jest.requireActual('~/lib/utils/simple_poll').default),
);
describe('MRWidgetMerging', () => {
let wrapper;
......@@ -11,6 +16,10 @@ describe('MRWidgetMerging', () => {
mr: {
targetBranchPath: '/branch-path',
targetBranch: 'branch',
transitionStateMachine() {},
},
service: {
poll: jest.fn().mockResolvedValue(),
},
},
stubs: {
......@@ -46,4 +55,20 @@ describe('MRWidgetMerging', () => {
expect(wrapper.find('a').attributes('href')).toBe('/branch-path');
});
describe('initiateMergePolling', () => {
it('should call simplePoll', () => {
wrapper.vm.initiateMergePolling();
expect(simplePoll).toHaveBeenCalledWith(expect.any(Function), { timeout: 0 });
});
it('should call handleMergePolling', () => {
jest.spyOn(wrapper.vm, 'handleMergePolling').mockImplementation(() => {});
wrapper.vm.initiateMergePolling();
expect(wrapper.vm.handleMergePolling).toHaveBeenCalled();
});
});
});
......@@ -328,7 +328,7 @@ describe('ReadyToMerge', () => {
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
jest.spyOn(wrapper.vm.service, 'merge').mockReturnValue(returnPromise('success'));
jest.spyOn(wrapper.vm, 'initiateMergePolling').mockImplementation(() => {});
jest.spyOn(wrapper.vm.mr, 'transitionStateMachine');
wrapper.vm.handleMergeButtonClick();
expect(eventHub.$emit).toHaveBeenCalledWith('StateMachineValueChanged', {
......@@ -337,7 +337,9 @@ describe('ReadyToMerge', () => {
setImmediate(() => {
expect(wrapper.vm.isMakingRequest).toBeTruthy();
expect(wrapper.vm.initiateMergePolling).toHaveBeenCalled();
expect(wrapper.vm.mr.transitionStateMachine).toHaveBeenCalledWith({
transition: 'start-merge',
});
const params = wrapper.vm.service.merge.mock.calls[0][0];
......@@ -348,26 +350,6 @@ describe('ReadyToMerge', () => {
});
});
describe('initiateMergePolling', () => {
it('should call simplePoll', () => {
createComponent();
wrapper.vm.initiateMergePolling();
expect(simplePoll).toHaveBeenCalledWith(expect.any(Function), { timeout: 0 });
});
it('should call handleMergePolling', () => {
createComponent();
jest.spyOn(wrapper.vm, 'handleMergePolling').mockImplementation(() => {});
wrapper.vm.initiateMergePolling();
expect(wrapper.vm.handleMergePolling).toHaveBeenCalled();
});
});
describe('initiateRemoveSourceBranchPolling', () => {
it('should emit event and call simplePoll', () => {
createComponent();
......
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