Merge branch '9186-implement-atmtwps-state-to-mr-widget' into 'master'
CE backport for gitlab-org/gitlab-ee!12156: Update the merge request widget's "Merge" button to support merge trains See merge request gitlab-org/gitlab-ce!27594
This commit is contained in:
commit
6cf619668b
14 changed files with 273 additions and 104 deletions
|
@ -1,15 +1,19 @@
|
||||||
<script>
|
<script>
|
||||||
|
import _ from 'underscore';
|
||||||
|
import autoMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/auto_merge';
|
||||||
import Flash from '../../../flash';
|
import Flash from '../../../flash';
|
||||||
import statusIcon from '../mr_widget_status_icon.vue';
|
import statusIcon from '../mr_widget_status_icon.vue';
|
||||||
import MrWidgetAuthor from '../../components/mr_widget_author.vue';
|
import MrWidgetAuthor from '../../components/mr_widget_author.vue';
|
||||||
import eventHub from '../../event_hub';
|
import eventHub from '../../event_hub';
|
||||||
|
import { AUTO_MERGE_STRATEGIES } from '../../constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MRWidgetMergeWhenPipelineSucceeds',
|
name: 'MRWidgetAutoMergeEnabled',
|
||||||
components: {
|
components: {
|
||||||
MrWidgetAuthor,
|
MrWidgetAuthor,
|
||||||
statusIcon,
|
statusIcon,
|
||||||
},
|
},
|
||||||
|
mixins: [autoMergeMixin],
|
||||||
props: {
|
props: {
|
||||||
mr: {
|
mr: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -57,7 +61,7 @@ export default {
|
||||||
removeSourceBranch() {
|
removeSourceBranch() {
|
||||||
const options = {
|
const options = {
|
||||||
sha: this.mr.sha,
|
sha: this.mr.sha,
|
||||||
auto_merge_strategy: 'merge_when_pipeline_succeeds',
|
auto_merge_strategy: this.mr.autoMergeStrategy,
|
||||||
should_remove_source_branch: true,
|
should_remove_source_branch: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -66,7 +70,7 @@ export default {
|
||||||
.merge(options)
|
.merge(options)
|
||||||
.then(res => res.data)
|
.then(res => res.data)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.status === 'merge_when_pipeline_succeeds') {
|
if (_.includes(AUTO_MERGE_STRATEGIES, data.status)) {
|
||||||
eventHub.$emit('MRWidgetUpdateRequested');
|
eventHub.$emit('MRWidgetUpdateRequested');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -84,9 +88,9 @@ export default {
|
||||||
<div class="media-body">
|
<div class="media-body">
|
||||||
<h4 class="d-flex align-items-start">
|
<h4 class="d-flex align-items-start">
|
||||||
<span class="append-right-10">
|
<span class="append-right-10">
|
||||||
{{ s__('mrWidget|Set by') }}
|
<span class="js-status-text-before-author">{{ statusTextBeforeAuthor }}</span>
|
||||||
<mr-widget-author :author="mr.setToAutoMergeBy" />
|
<mr-widget-author :author="mr.setToAutoMergeBy" />
|
||||||
{{ s__('mrWidget|to be merged automatically when the pipeline succeeds') }}
|
<span class="js-status-text-after-author">{{ statusTextAfterAuthor }}</span>
|
||||||
</span>
|
</span>
|
||||||
<a
|
<a
|
||||||
v-if="mr.canCancelAutomaticMerge"
|
v-if="mr.canCancelAutomaticMerge"
|
||||||
|
@ -97,7 +101,7 @@ export default {
|
||||||
@click.prevent="cancelAutomaticMerge"
|
@click.prevent="cancelAutomaticMerge"
|
||||||
>
|
>
|
||||||
<i v-if="isCancellingAutoMerge" class="fa fa-spinner fa-spin" aria-hidden="true"> </i>
|
<i v-if="isCancellingAutoMerge" class="fa fa-spinner fa-spin" aria-hidden="true"> </i>
|
||||||
{{ s__('mrWidget|Cancel automatic merge') }}
|
{{ cancelButtonText }}
|
||||||
</a>
|
</a>
|
||||||
</h4>
|
</h4>
|
||||||
<section class="mr-info-list">
|
<section class="mr-info-list">
|
|
@ -1,4 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
|
import _ from 'underscore';
|
||||||
import successSvg from 'icons/_icon_status_success.svg';
|
import successSvg from 'icons/_icon_status_success.svg';
|
||||||
import warningSvg from 'icons/_icon_status_warning.svg';
|
import warningSvg from 'icons/_icon_status_warning.svg';
|
||||||
import simplePoll from '~/lib/utils/simple_poll';
|
import simplePoll from '~/lib/utils/simple_poll';
|
||||||
|
@ -12,6 +13,7 @@ import SquashBeforeMerge from './squash_before_merge.vue';
|
||||||
import CommitsHeader from './commits_header.vue';
|
import CommitsHeader from './commits_header.vue';
|
||||||
import CommitEdit from './commit_edit.vue';
|
import CommitEdit from './commit_edit.vue';
|
||||||
import CommitMessageDropdown from './commit_message_dropdown.vue';
|
import CommitMessageDropdown from './commit_message_dropdown.vue';
|
||||||
|
import { AUTO_MERGE_STRATEGIES } from '../../constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ReadyToMerge',
|
name: 'ReadyToMerge',
|
||||||
|
@ -30,8 +32,6 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
removeSourceBranch: this.mr.shouldRemoveSourceBranch,
|
removeSourceBranch: this.mr.shouldRemoveSourceBranch,
|
||||||
mergeWhenBuildSucceeds: false,
|
|
||||||
autoMergeStrategy: undefined,
|
|
||||||
isMakingRequest: false,
|
isMakingRequest: false,
|
||||||
isMergingImmediately: false,
|
isMergingImmediately: false,
|
||||||
commitMessage: this.mr.commitMessage,
|
commitMessage: this.mr.commitMessage,
|
||||||
|
@ -42,18 +42,18 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
shouldShowAutoMergeText() {
|
isAutoMergeAvailable() {
|
||||||
return this.mr.isPipelineActive;
|
return !_.isEmpty(this.mr.availableAutoMergeStrategies);
|
||||||
},
|
},
|
||||||
status() {
|
status() {
|
||||||
const { pipeline, isPipelineActive, isPipelineFailed, hasCI, ciStatus } = this.mr;
|
const { pipeline, isPipelineFailed, hasCI, ciStatus } = this.mr;
|
||||||
|
|
||||||
if (hasCI && !ciStatus) {
|
if (hasCI && !ciStatus) {
|
||||||
return 'failed';
|
return 'failed';
|
||||||
|
} else if (this.isAutoMergeAvailable) {
|
||||||
|
return 'pending';
|
||||||
} else if (!pipeline) {
|
} else if (!pipeline) {
|
||||||
return 'success';
|
return 'success';
|
||||||
} else if (isPipelineActive) {
|
|
||||||
return 'pending';
|
|
||||||
} else if (isPipelineFailed) {
|
} else if (isPipelineFailed) {
|
||||||
return 'failed';
|
return 'failed';
|
||||||
}
|
}
|
||||||
|
@ -87,14 +87,14 @@ export default {
|
||||||
mergeButtonText() {
|
mergeButtonText() {
|
||||||
if (this.isMergingImmediately) {
|
if (this.isMergingImmediately) {
|
||||||
return __('Merge in progress');
|
return __('Merge in progress');
|
||||||
} else if (this.shouldShowAutoMergeText) {
|
} else if (this.isAutoMergeAvailable) {
|
||||||
return __('Merge when pipeline succeeds');
|
return this.autoMergeText;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Merge';
|
return __('Merge');
|
||||||
},
|
},
|
||||||
shouldShowMergeOptionsDropdown() {
|
shouldShowMergeOptionsDropdown() {
|
||||||
return this.mr.isPipelineActive && !this.mr.onlyAllowMergeIfPipelineSucceeds;
|
return this.isAutoMergeAvailable && !this.mr.onlyAllowMergeIfPipelineSucceeds;
|
||||||
},
|
},
|
||||||
isRemoveSourceBranchButtonDisabled() {
|
isRemoveSourceBranchButtonDisabled() {
|
||||||
return this.isMergeButtonDisabled;
|
return this.isMergeButtonDisabled;
|
||||||
|
@ -104,7 +104,7 @@ export default {
|
||||||
return enableSquashBeforeMerge && commitsCount > 1;
|
return enableSquashBeforeMerge && commitsCount > 1;
|
||||||
},
|
},
|
||||||
shouldShowMergeControls() {
|
shouldShowMergeControls() {
|
||||||
return this.mr.isMergeAllowed || this.shouldShowAutoMergeText;
|
return this.mr.isMergeAllowed || this.isAutoMergeAvailable;
|
||||||
},
|
},
|
||||||
shouldShowSquashEdit() {
|
shouldShowSquashEdit() {
|
||||||
return this.squashBeforeMerge && this.shouldShowSquashBeforeMerge;
|
return this.squashBeforeMerge && this.shouldShowSquashBeforeMerge;
|
||||||
|
@ -118,20 +118,15 @@ export default {
|
||||||
const { commitMessageWithDescription, commitMessage } = this.mr;
|
const { commitMessageWithDescription, commitMessage } = this.mr;
|
||||||
this.commitMessage = includeDescription ? commitMessageWithDescription : commitMessage;
|
this.commitMessage = includeDescription ? commitMessageWithDescription : commitMessage;
|
||||||
},
|
},
|
||||||
handleMergeButtonClick(mergeWhenBuildSucceeds, mergeImmediately) {
|
handleMergeButtonClick(useAutoMerge, mergeImmediately = false) {
|
||||||
// TODO: Remove no-param-reassign
|
if (mergeImmediately) {
|
||||||
if (mergeWhenBuildSucceeds === undefined) {
|
|
||||||
mergeWhenBuildSucceeds = this.mr.isPipelineActive; // eslint-disable-line no-param-reassign
|
|
||||||
} else if (mergeImmediately) {
|
|
||||||
this.isMergingImmediately = true;
|
this.isMergingImmediately = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.autoMergeStrategy = mergeWhenBuildSucceeds ? 'merge_when_pipeline_succeeds' : undefined;
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
sha: this.mr.sha,
|
sha: this.mr.sha,
|
||||||
commit_message: this.commitMessage,
|
commit_message: this.commitMessage,
|
||||||
auto_merge_strategy: this.autoMergeStrategy,
|
auto_merge_strategy: useAutoMerge ? this.mr.preferredAutoMergeStrategy : undefined,
|
||||||
should_remove_source_branch: this.removeSourceBranch === true,
|
should_remove_source_branch: this.removeSourceBranch === true,
|
||||||
squash: this.squashBeforeMerge,
|
squash: this.squashBeforeMerge,
|
||||||
squash_commit_message: this.squashCommitMessage,
|
squash_commit_message: this.squashCommitMessage,
|
||||||
|
@ -144,7 +139,7 @@ export default {
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const hasError = data.status === 'failed' || data.status === 'hook_validation_error';
|
const hasError = data.status === 'failed' || data.status === 'hook_validation_error';
|
||||||
|
|
||||||
if (data.status === 'merge_when_pipeline_succeeds') {
|
if (_.includes(AUTO_MERGE_STRATEGIES, data.status)) {
|
||||||
eventHub.$emit('MRWidgetUpdateRequested');
|
eventHub.$emit('MRWidgetUpdateRequested');
|
||||||
} else if (data.status === 'success') {
|
} else if (data.status === 'success') {
|
||||||
this.initiateMergePolling();
|
this.initiateMergePolling();
|
||||||
|
@ -242,13 +237,13 @@ export default {
|
||||||
:class="mergeButtonClass"
|
:class="mergeButtonClass"
|
||||||
type="button"
|
type="button"
|
||||||
class="qa-merge-button"
|
class="qa-merge-button"
|
||||||
@click="handleMergeButtonClick()"
|
@click="handleMergeButtonClick(isAutoMergeAvailable)"
|
||||||
>
|
>
|
||||||
<i v-if="isMakingRequest" class="fa fa-spinner fa-spin" aria-hidden="true"></i>
|
<i v-if="isMakingRequest" class="fa fa-spinner fa-spin" aria-hidden="true"></i>
|
||||||
{{ mergeButtonText }}
|
{{ mergeButtonText }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="shouldShowMergeOptionsDropdown"
|
v-if="isAutoMergeAvailable"
|
||||||
:disabled="isMergeButtonDisabled"
|
:disabled="isMergeButtonDisabled"
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-sm btn-info dropdown-toggle js-merge-moment"
|
class="btn btn-sm btn-info dropdown-toggle js-merge-moment"
|
||||||
|
@ -264,15 +259,13 @@ export default {
|
||||||
>
|
>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
class="merge_when_pipeline_succeeds qa-merge-when-pipeline-succeeds-option"
|
class="auto_merge_enabled qa-merge-when-pipeline-succeeds-option"
|
||||||
href="#"
|
href="#"
|
||||||
@click.prevent="handleMergeButtonClick(true)"
|
@click.prevent="handleMergeButtonClick(true)"
|
||||||
>
|
>
|
||||||
<span class="media">
|
<span class="media">
|
||||||
<span class="merge-opt-icon" aria-hidden="true" v-html="successSvg"></span>
|
<span class="merge-opt-icon" aria-hidden="true" v-html="successSvg"></span>
|
||||||
<span class="media-body merge-opt-title">{{
|
<span class="media-body merge-opt-title">{{ autoMergeText }}</span>
|
||||||
__('Merge when pipeline succeeds')
|
|
||||||
}}</span>
|
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -3,3 +3,13 @@ export const DANGER = 'danger';
|
||||||
|
|
||||||
export const WARNING_MESSAGE_CLASS = 'warning_message';
|
export const WARNING_MESSAGE_CLASS = 'warning_message';
|
||||||
export const DANGER_MESSAGE_CLASS = 'danger_message';
|
export const DANGER_MESSAGE_CLASS = 'danger_message';
|
||||||
|
|
||||||
|
export const MWPS_MERGE_STRATEGY = 'merge_when_pipeline_succeeds';
|
||||||
|
export const ATMTWPS_MERGE_STRATEGY = 'add_to_merge_train_when_pipeline_succeeds';
|
||||||
|
export const MT_MERGE_STRATEGY = 'merge_train';
|
||||||
|
|
||||||
|
export const AUTO_MERGE_STRATEGIES = [
|
||||||
|
MWPS_MERGE_STRATEGY,
|
||||||
|
ATMTWPS_MERGE_STRATEGY,
|
||||||
|
MT_MERGE_STRATEGY,
|
||||||
|
];
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { s__ } from '~/locale';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
statusTextBeforeAuthor() {
|
||||||
|
return s__('mrWidget|Set by');
|
||||||
|
},
|
||||||
|
statusTextAfterAuthor() {
|
||||||
|
return s__('mrWidget|to be merged automatically when the pipeline succeeds');
|
||||||
|
},
|
||||||
|
cancelButtonText() {
|
||||||
|
return s__('mrWidget|Cancel automatic merge');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { __ } from '~/locale';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
computed: {
|
computed: {
|
||||||
isMergeButtonDisabled() {
|
isMergeButtonDisabled() {
|
||||||
|
@ -9,5 +11,9 @@ export default {
|
||||||
this.mr.preventMerge,
|
this.mr.preventMerge,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
autoMergeText() {
|
||||||
|
// MWPS is currently the only auto merge strategy available in CE
|
||||||
|
return __('Merge when pipeline succeeds');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -29,7 +29,7 @@ import UnresolvedDiscussionsState from './components/states/unresolved_discussio
|
||||||
import PipelineBlockedState from './components/states/mr_widget_pipeline_blocked.vue';
|
import PipelineBlockedState from './components/states/mr_widget_pipeline_blocked.vue';
|
||||||
import PipelineFailedState from './components/states/pipeline_failed.vue';
|
import PipelineFailedState from './components/states/pipeline_failed.vue';
|
||||||
import FailedToMerge from './components/states/mr_widget_failed_to_merge.vue';
|
import FailedToMerge from './components/states/mr_widget_failed_to_merge.vue';
|
||||||
import MergeWhenPipelineSucceedsState from './components/states/mr_widget_merge_when_pipeline_succeeds.vue';
|
import MrWidgetAutoMergeEnabled from './components/states/mr_widget_auto_merge_enabled.vue';
|
||||||
import AutoMergeFailed from './components/states/mr_widget_auto_merge_failed.vue';
|
import AutoMergeFailed from './components/states/mr_widget_auto_merge_failed.vue';
|
||||||
import CheckingState from './components/states/mr_widget_checking.vue';
|
import CheckingState from './components/states/mr_widget_checking.vue';
|
||||||
import eventHub from './event_hub';
|
import eventHub from './event_hub';
|
||||||
|
@ -64,7 +64,7 @@ export default {
|
||||||
'mr-widget-unresolved-discussions': UnresolvedDiscussionsState,
|
'mr-widget-unresolved-discussions': UnresolvedDiscussionsState,
|
||||||
'mr-widget-pipeline-blocked': PipelineBlockedState,
|
'mr-widget-pipeline-blocked': PipelineBlockedState,
|
||||||
'mr-widget-pipeline-failed': PipelineFailedState,
|
'mr-widget-pipeline-failed': PipelineFailedState,
|
||||||
'mr-widget-merge-when-pipeline-succeeds': MergeWhenPipelineSucceedsState,
|
MrWidgetAutoMergeEnabled,
|
||||||
'mr-widget-auto-merge-failed': AutoMergeFailed,
|
'mr-widget-auto-merge-failed': AutoMergeFailed,
|
||||||
'mr-widget-rebase': RebaseState,
|
'mr-widget-rebase': RebaseState,
|
||||||
SourceBranchRemovalStatus,
|
SourceBranchRemovalStatus,
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import Timeago from 'timeago.js';
|
import Timeago from 'timeago.js';
|
||||||
|
import _ from 'underscore';
|
||||||
import getStateKey from 'ee_else_ce/vue_merge_request_widget/stores/get_state_key';
|
import getStateKey from 'ee_else_ce/vue_merge_request_widget/stores/get_state_key';
|
||||||
import { stateKey } from './state_maps';
|
import { stateKey } from './state_maps';
|
||||||
import { formatDate } from '../../lib/utils/datetime_utility';
|
import { formatDate } from '../../lib/utils/datetime_utility';
|
||||||
|
import { ATMTWPS_MERGE_STRATEGY, MT_MERGE_STRATEGY, MWPS_MERGE_STRATEGY } from '../constants';
|
||||||
|
|
||||||
export default class MergeRequestStore {
|
export default class MergeRequestStore {
|
||||||
constructor(data) {
|
constructor(data) {
|
||||||
|
@ -77,6 +79,10 @@ export default class MergeRequestStore {
|
||||||
this.onlyAllowMergeIfPipelineSucceeds = data.only_allow_merge_if_pipeline_succeeds || false;
|
this.onlyAllowMergeIfPipelineSucceeds = data.only_allow_merge_if_pipeline_succeeds || false;
|
||||||
this.autoMergeEnabled = Boolean(data.auto_merge_enabled);
|
this.autoMergeEnabled = Boolean(data.auto_merge_enabled);
|
||||||
this.autoMergeStrategy = data.auto_merge_strategy;
|
this.autoMergeStrategy = data.auto_merge_strategy;
|
||||||
|
this.availableAutoMergeStrategies = data.available_auto_merge_strategies;
|
||||||
|
this.preferredAutoMergeStrategy = MergeRequestStore.getPreferredAutoMergeStrategy(
|
||||||
|
this.availableAutoMergeStrategies,
|
||||||
|
);
|
||||||
this.mergePath = data.merge_path;
|
this.mergePath = data.merge_path;
|
||||||
this.ffOnlyEnabled = data.ff_only_enabled;
|
this.ffOnlyEnabled = data.ff_only_enabled;
|
||||||
this.shouldBeRebased = Boolean(data.should_be_rebased);
|
this.shouldBeRebased = Boolean(data.should_be_rebased);
|
||||||
|
@ -104,7 +110,9 @@ export default class MergeRequestStore {
|
||||||
this.sourceProjectFullPath = data.source_project_full_path;
|
this.sourceProjectFullPath = data.source_project_full_path;
|
||||||
this.sourceProjectId = data.source_project_id;
|
this.sourceProjectId = data.source_project_id;
|
||||||
this.targetProjectId = data.target_project_id;
|
this.targetProjectId = data.target_project_id;
|
||||||
this.mergePipelinesEnabled = data.merge_pipelines_enabled;
|
this.mergePipelinesEnabled = Boolean(data.merge_pipelines_enabled);
|
||||||
|
this.mergeTrainsCount = data.merge_trains_count || 0;
|
||||||
|
this.mergeTrainIndex = data.merge_train_index;
|
||||||
|
|
||||||
// Cherry-pick and Revert actions related
|
// Cherry-pick and Revert actions related
|
||||||
this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false;
|
this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false;
|
||||||
|
@ -204,4 +212,16 @@ export default class MergeRequestStore {
|
||||||
|
|
||||||
return timeagoInstance.format(date);
|
return timeagoInstance.format(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getPreferredAutoMergeStrategy(availableAutoMergeStrategies) {
|
||||||
|
if (_.includes(availableAutoMergeStrategies, ATMTWPS_MERGE_STRATEGY)) {
|
||||||
|
return ATMTWPS_MERGE_STRATEGY;
|
||||||
|
} else if (_.includes(availableAutoMergeStrategies, MT_MERGE_STRATEGY)) {
|
||||||
|
return MT_MERGE_STRATEGY;
|
||||||
|
} else if (_.includes(availableAutoMergeStrategies, MWPS_MERGE_STRATEGY)) {
|
||||||
|
return MWPS_MERGE_STRATEGY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ const stateToComponentMap = {
|
||||||
unresolvedDiscussions: 'mr-widget-unresolved-discussions',
|
unresolvedDiscussions: 'mr-widget-unresolved-discussions',
|
||||||
pipelineBlocked: 'mr-widget-pipeline-blocked',
|
pipelineBlocked: 'mr-widget-pipeline-blocked',
|
||||||
pipelineFailed: 'mr-widget-pipeline-failed',
|
pipelineFailed: 'mr-widget-pipeline-failed',
|
||||||
autoMergeEnabled: 'mr-widget-merge-when-pipeline-succeeds',
|
autoMergeEnabled: 'mr-widget-auto-merge-enabled',
|
||||||
failedToMerge: 'mr-widget-failed-to-merge',
|
failedToMerge: 'mr-widget-failed-to-merge',
|
||||||
autoMergeFailed: 'mr-widget-auto-merge-failed',
|
autoMergeFailed: 'mr-widget-auto-merge-failed',
|
||||||
shaMismatch: 'sha-mismatch',
|
shaMismatch: 'sha-mismatch',
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Update the merge request widget's "Merge" button to support merge trains
|
||||||
|
merge_request: 27594
|
||||||
|
author:
|
||||||
|
type: added
|
|
@ -6045,6 +6045,9 @@ msgstr ""
|
||||||
msgid "Members of <strong>%{project_name}</strong>"
|
msgid "Members of <strong>%{project_name}</strong>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Merge"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Merge Request"
|
msgid "Merge Request"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,19 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import mwpsComponent from '~/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue';
|
import autoMergeEnabledComponent from '~/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue';
|
||||||
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
|
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
|
||||||
import eventHub from '~/vue_merge_request_widget/event_hub';
|
import eventHub from '~/vue_merge_request_widget/event_hub';
|
||||||
import mountComponent from 'spec/helpers/vue_mount_component_helper';
|
import mountComponent from 'spec/helpers/vue_mount_component_helper';
|
||||||
|
import { trimText } from 'spec/helpers/text_helper';
|
||||||
|
import { MWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants';
|
||||||
|
|
||||||
describe('MRWidgetMergeWhenPipelineSucceeds', () => {
|
describe('MRWidgetAutoMergeEnabled', () => {
|
||||||
let vm;
|
let vm;
|
||||||
const targetBranchPath = '/foo/bar';
|
const targetBranchPath = '/foo/bar';
|
||||||
const targetBranch = 'foo';
|
const targetBranch = 'foo';
|
||||||
const sha = '1EA2EZ34';
|
const sha = '1EA2EZ34';
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const Component = Vue.extend(mwpsComponent);
|
const Component = Vue.extend(autoMergeEnabledComponent);
|
||||||
spyOn(eventHub, '$emit');
|
spyOn(eventHub, '$emit');
|
||||||
|
|
||||||
vm = mountComponent(Component, {
|
vm = mountComponent(Component, {
|
||||||
|
@ -25,6 +27,7 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
|
||||||
sha,
|
sha,
|
||||||
targetBranchPath,
|
targetBranchPath,
|
||||||
targetBranch,
|
targetBranch,
|
||||||
|
autoMergeStrategy: MWPS_MERGE_STRATEGY,
|
||||||
},
|
},
|
||||||
service: new MRWidgetService({}),
|
service: new MRWidgetService({}),
|
||||||
});
|
});
|
||||||
|
@ -66,6 +69,32 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
|
||||||
expect(vm.canRemoveSourceBranch).toBeFalsy();
|
expect(vm.canRemoveSourceBranch).toBeFalsy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('statusTextBeforeAuthor', () => {
|
||||||
|
it('should return "Set by" if the MWPS is selected', () => {
|
||||||
|
Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY);
|
||||||
|
|
||||||
|
expect(vm.statusTextBeforeAuthor).toBe('Set by');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('statusTextAfterAuthor', () => {
|
||||||
|
it('should return "to be merged automatically..." if MWPS is selected', () => {
|
||||||
|
Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY);
|
||||||
|
|
||||||
|
expect(vm.statusTextAfterAuthor).toBe(
|
||||||
|
'to be merged automatically when the pipeline succeeds',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cancelButtonText', () => {
|
||||||
|
it('should return "Cancel automatic merge" if MWPS is selected', () => {
|
||||||
|
Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY);
|
||||||
|
|
||||||
|
expect(vm.cancelButtonText).toBe('Cancel automatic merge');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('methods', () => {
|
describe('methods', () => {
|
||||||
|
@ -96,7 +125,7 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
|
||||||
spyOn(vm.service, 'merge').and.returnValue(
|
spyOn(vm.service, 'merge').and.returnValue(
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
data: {
|
data: {
|
||||||
status: 'merge_when_pipeline_succeeds',
|
status: MWPS_MERGE_STRATEGY,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -106,7 +135,7 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
|
||||||
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
|
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
|
||||||
expect(vm.service.merge).toHaveBeenCalledWith({
|
expect(vm.service.merge).toHaveBeenCalledWith({
|
||||||
sha,
|
sha,
|
||||||
auto_merge_strategy: 'merge_when_pipeline_succeeds',
|
auto_merge_strategy: MWPS_MERGE_STRATEGY,
|
||||||
should_remove_source_branch: true,
|
should_remove_source_branch: true,
|
||||||
});
|
});
|
||||||
done();
|
done();
|
||||||
|
@ -119,6 +148,7 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
|
||||||
it('should have correct elements', () => {
|
it('should have correct elements', () => {
|
||||||
expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy();
|
expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy();
|
||||||
expect(vm.$el.innerText).toContain('to be merged automatically when the pipeline succeeds');
|
expect(vm.$el.innerText).toContain('to be merged automatically when the pipeline succeeds');
|
||||||
|
|
||||||
expect(vm.$el.innerText).toContain('The changes will be merged into');
|
expect(vm.$el.innerText).toContain('The changes will be merged into');
|
||||||
expect(vm.$el.innerText).toContain(targetBranch);
|
expect(vm.$el.innerText).toContain(targetBranch);
|
||||||
expect(vm.$el.innerText).toContain('The source branch will not be deleted');
|
expect(vm.$el.innerText).toContain('The source branch will not be deleted');
|
||||||
|
@ -174,5 +204,27 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render the status text as "...to merged automatically" if MWPS is selected', done => {
|
||||||
|
Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY);
|
||||||
|
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
const statusText = trimText(vm.$el.querySelector('.js-status-text-after-author').innerText);
|
||||||
|
|
||||||
|
expect(statusText).toBe('to be merged automatically when the pipeline succeeds');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render the cancel button as "Cancel automatic merge" if MWPS is selected', done => {
|
||||||
|
Vue.set(vm.mr, 'autoMergeStrategy', MWPS_MERGE_STRATEGY);
|
||||||
|
|
||||||
|
Vue.nextTick(() => {
|
||||||
|
const cancelButtonText = trimText(vm.$el.querySelector('.js-cancel-auto-merge').innerText);
|
||||||
|
|
||||||
|
expect(cancelButtonText).toBe('Cancel automatic merge');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -6,6 +6,7 @@ import CommitEdit from '~/vue_merge_request_widget/components/states/commit_edit
|
||||||
import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/commit_message_dropdown.vue';
|
import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/commit_message_dropdown.vue';
|
||||||
import eventHub from '~/vue_merge_request_widget/event_hub';
|
import eventHub from '~/vue_merge_request_widget/event_hub';
|
||||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||||
|
import { MWPS_MERGE_STRATEGY, ATMTWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants';
|
||||||
|
|
||||||
const commitMessage = 'This is the commit message';
|
const commitMessage = 'This is the commit message';
|
||||||
const squashCommitMessage = 'This is the squash commit message';
|
const squashCommitMessage = 'This is the squash commit message';
|
||||||
|
@ -29,6 +30,8 @@ const createTestMr = customConfig => {
|
||||||
shouldRemoveSourceBranch: true,
|
shouldRemoveSourceBranch: true,
|
||||||
canRemoveSourceBranch: false,
|
canRemoveSourceBranch: false,
|
||||||
targetBranch: 'master',
|
targetBranch: 'master',
|
||||||
|
preferredAutoMergeStrategy: MWPS_MERGE_STRATEGY,
|
||||||
|
availableAutoMergeStrategies: [MWPS_MERGE_STRATEGY],
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.assign(mr, customConfig.mr);
|
Object.assign(mr, customConfig.mr);
|
||||||
|
@ -80,7 +83,6 @@ describe('ReadyToMerge', () => {
|
||||||
it('should have default data', () => {
|
it('should have default data', () => {
|
||||||
expect(vm.mergeWhenBuildSucceeds).toBeFalsy();
|
expect(vm.mergeWhenBuildSucceeds).toBeFalsy();
|
||||||
expect(vm.useCommitMessageWithDescription).toBeFalsy();
|
expect(vm.useCommitMessageWithDescription).toBeFalsy();
|
||||||
expect(vm.autoMergeStrategy).toBeUndefined();
|
|
||||||
expect(vm.showCommitMessageEditor).toBeFalsy();
|
expect(vm.showCommitMessageEditor).toBeFalsy();
|
||||||
expect(vm.isMakingRequest).toBeFalsy();
|
expect(vm.isMakingRequest).toBeFalsy();
|
||||||
expect(vm.isMergingImmediately).toBeFalsy();
|
expect(vm.isMergingImmediately).toBeFalsy();
|
||||||
|
@ -91,47 +93,51 @@ describe('ReadyToMerge', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('computed', () => {
|
describe('computed', () => {
|
||||||
describe('shouldShowAutoMergeText', () => {
|
describe('isAutoMergeAvailable', () => {
|
||||||
it('should return true with active pipeline', () => {
|
it('should return true when at least one merge strategy is available', () => {
|
||||||
vm.mr.isPipelineActive = true;
|
vm.mr.availableAutoMergeStrategies = [MWPS_MERGE_STRATEGY];
|
||||||
|
|
||||||
expect(vm.shouldShowAutoMergeText).toBeTruthy();
|
expect(vm.isAutoMergeAvailable).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false with inactive pipeline', () => {
|
it('should return false when no merge strategies are available', () => {
|
||||||
vm.mr.isPipelineActive = false;
|
vm.mr.availableAutoMergeStrategies = [];
|
||||||
|
|
||||||
expect(vm.shouldShowAutoMergeText).toBeFalsy();
|
expect(vm.isAutoMergeAvailable).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('status', () => {
|
describe('status', () => {
|
||||||
it('defaults to success', () => {
|
it('defaults to success', () => {
|
||||||
vm.mr.pipeline = true;
|
Vue.set(vm.mr, 'pipeline', true);
|
||||||
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
|
||||||
|
|
||||||
expect(vm.status).toEqual('success');
|
expect(vm.status).toEqual('success');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns failed when MR has CI but also has an unknown status', () => {
|
it('returns failed when MR has CI but also has an unknown status', () => {
|
||||||
vm.mr.hasCI = true;
|
Vue.set(vm.mr, 'hasCI', true);
|
||||||
|
|
||||||
expect(vm.status).toEqual('failed');
|
expect(vm.status).toEqual('failed');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns default when MR has no pipeline', () => {
|
it('returns default when MR has no pipeline', () => {
|
||||||
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
|
||||||
|
|
||||||
expect(vm.status).toEqual('success');
|
expect(vm.status).toEqual('success');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns pending when pipeline is active', () => {
|
it('returns pending when pipeline is active', () => {
|
||||||
vm.mr.pipeline = {};
|
Vue.set(vm.mr, 'pipeline', {});
|
||||||
vm.mr.isPipelineActive = true;
|
Vue.set(vm.mr, 'isPipelineActive', true);
|
||||||
|
|
||||||
expect(vm.status).toEqual('pending');
|
expect(vm.status).toEqual('pending');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns failed when pipeline is failed', () => {
|
it('returns failed when pipeline is failed', () => {
|
||||||
vm.mr.pipeline = {};
|
Vue.set(vm.mr, 'pipeline', {});
|
||||||
vm.mr.isPipelineFailed = true;
|
Vue.set(vm.mr, 'isPipelineFailed', true);
|
||||||
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
|
||||||
|
|
||||||
expect(vm.status).toEqual('failed');
|
expect(vm.status).toEqual('failed');
|
||||||
});
|
});
|
||||||
|
@ -143,18 +149,20 @@ describe('ReadyToMerge', () => {
|
||||||
const inActionClass = `${defaultClass} btn-info`;
|
const inActionClass = `${defaultClass} btn-info`;
|
||||||
|
|
||||||
it('defaults to success class', () => {
|
it('defaults to success class', () => {
|
||||||
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
|
||||||
|
|
||||||
expect(vm.mergeButtonClass).toEqual(defaultClass);
|
expect(vm.mergeButtonClass).toEqual(defaultClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns success class for success status', () => {
|
it('returns success class for success status', () => {
|
||||||
vm.mr.pipeline = true;
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
|
||||||
|
Vue.set(vm.mr, 'pipeline', true);
|
||||||
|
|
||||||
expect(vm.mergeButtonClass).toEqual(defaultClass);
|
expect(vm.mergeButtonClass).toEqual(defaultClass);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns info class for pending status', () => {
|
it('returns info class for pending status', () => {
|
||||||
vm.mr.pipeline = {};
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', [ATMTWPS_MERGE_STRATEGY]);
|
||||||
vm.mr.isPipelineActive = true;
|
|
||||||
|
|
||||||
expect(vm.mergeButtonClass).toEqual(inActionClass);
|
expect(vm.mergeButtonClass).toEqual(inActionClass);
|
||||||
});
|
});
|
||||||
|
@ -198,69 +206,82 @@ describe('ReadyToMerge', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('mergeButtonText', () => {
|
describe('mergeButtonText', () => {
|
||||||
it('should return Merge', () => {
|
it('should return "Merge" when no auto merge strategies are available', () => {
|
||||||
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
|
||||||
|
|
||||||
expect(vm.mergeButtonText).toEqual('Merge');
|
expect(vm.mergeButtonText).toEqual('Merge');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return Merge in progress', () => {
|
it('should return "Merge in progress"', () => {
|
||||||
vm.isMergingImmediately = true;
|
Vue.set(vm, 'isMergingImmediately', true);
|
||||||
|
|
||||||
expect(vm.mergeButtonText).toEqual('Merge in progress');
|
expect(vm.mergeButtonText).toEqual('Merge in progress');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return Merge when pipeline succeeds', () => {
|
it('should return "Merge when pipeline succeeds" when the MWPS auto merge strategy is available', () => {
|
||||||
vm.isMergingImmediately = false;
|
Vue.set(vm, 'isMergingImmediately', false);
|
||||||
vm.mr.isPipelineActive = true;
|
Vue.set(vm.mr, 'preferredAutoMergeStrategy', MWPS_MERGE_STRATEGY);
|
||||||
|
|
||||||
expect(vm.mergeButtonText).toEqual('Merge when pipeline succeeds');
|
expect(vm.mergeButtonText).toEqual('Merge when pipeline succeeds');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('autoMergeText', () => {
|
||||||
|
it('should return Merge when pipeline succeeds', () => {
|
||||||
|
Vue.set(vm.mr, 'preferredAutoMergeStrategy', MWPS_MERGE_STRATEGY);
|
||||||
|
|
||||||
|
expect(vm.autoMergeText).toEqual('Merge when pipeline succeeds');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('shouldShowMergeOptionsDropdown', () => {
|
describe('shouldShowMergeOptionsDropdown', () => {
|
||||||
it('should return false with initial data', () => {
|
it('should return false when no auto merge strategies are available', () => {
|
||||||
expect(vm.shouldShowMergeOptionsDropdown).toBeFalsy();
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
|
||||||
|
|
||||||
|
expect(vm.shouldShowMergeOptionsDropdown).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when pipeline active', () => {
|
it('should return true when at least one auto merge strategy is available', () => {
|
||||||
vm.mr.isPipelineActive = true;
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', [ATMTWPS_MERGE_STRATEGY]);
|
||||||
|
|
||||||
expect(vm.shouldShowMergeOptionsDropdown).toBeTruthy();
|
expect(vm.shouldShowMergeOptionsDropdown).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return false when pipeline active but only merge when pipeline succeeds set in project options', () => {
|
it('should return false when pipeline active but only merge when pipeline succeeds set in project options', () => {
|
||||||
vm.mr.isPipelineActive = true;
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', [ATMTWPS_MERGE_STRATEGY]);
|
||||||
vm.mr.onlyAllowMergeIfPipelineSucceeds = true;
|
Vue.set(vm.mr, 'onlyAllowMergeIfPipelineSucceeds', true);
|
||||||
|
|
||||||
expect(vm.shouldShowMergeOptionsDropdown).toBeFalsy();
|
expect(vm.shouldShowMergeOptionsDropdown).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isMergeButtonDisabled', () => {
|
describe('isMergeButtonDisabled', () => {
|
||||||
it('should return false with initial data', () => {
|
it('should return false with initial data', () => {
|
||||||
vm.mr.isMergeAllowed = true;
|
Vue.set(vm.mr, 'isMergeAllowed', true);
|
||||||
|
|
||||||
expect(vm.isMergeButtonDisabled).toBeFalsy();
|
expect(vm.isMergeButtonDisabled).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when there is no commit message', () => {
|
it('should return true when there is no commit message', () => {
|
||||||
vm.mr.isMergeAllowed = true;
|
Vue.set(vm.mr, 'isMergeAllowed', true);
|
||||||
vm.commitMessage = '';
|
Vue.set(vm, 'commitMessage', '');
|
||||||
|
|
||||||
expect(vm.isMergeButtonDisabled).toBeTruthy();
|
expect(vm.isMergeButtonDisabled).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true if merge is not allowed', () => {
|
it('should return true if merge is not allowed', () => {
|
||||||
vm.mr.isMergeAllowed = false;
|
Vue.set(vm.mr, 'isMergeAllowed', false);
|
||||||
vm.mr.onlyAllowMergeIfPipelineSucceeds = true;
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
|
||||||
|
Vue.set(vm.mr, 'onlyAllowMergeIfPipelineSucceeds', true);
|
||||||
|
|
||||||
expect(vm.isMergeButtonDisabled).toBeTruthy();
|
expect(vm.isMergeButtonDisabled).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when the vm instance is making request', () => {
|
it('should return true when the vm instance is making request', () => {
|
||||||
vm.mr.isMergeAllowed = true;
|
Vue.set(vm.mr, 'isMergeAllowed', true);
|
||||||
vm.isMakingRequest = true;
|
Vue.set(vm, 'isMakingRequest', true);
|
||||||
|
|
||||||
expect(vm.isMergeButtonDisabled).toBeTruthy();
|
expect(vm.isMergeButtonDisabled).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -268,31 +289,31 @@ describe('ReadyToMerge', () => {
|
||||||
describe('methods', () => {
|
describe('methods', () => {
|
||||||
describe('shouldShowMergeControls', () => {
|
describe('shouldShowMergeControls', () => {
|
||||||
it('should return false when an external pipeline is running and required to succeed', () => {
|
it('should return false when an external pipeline is running and required to succeed', () => {
|
||||||
vm.mr.isMergeAllowed = false;
|
Vue.set(vm.mr, 'isMergeAllowed', false);
|
||||||
vm.mr.isPipelineActive = false;
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
|
||||||
|
|
||||||
expect(vm.shouldShowMergeControls).toBeFalsy();
|
expect(vm.shouldShowMergeControls).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when the build succeeded or build not required to succeed', () => {
|
it('should return true when the build succeeded or build not required to succeed', () => {
|
||||||
vm.mr.isMergeAllowed = true;
|
Vue.set(vm.mr, 'isMergeAllowed', true);
|
||||||
vm.mr.isPipelineActive = false;
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', []);
|
||||||
|
|
||||||
expect(vm.shouldShowMergeControls).toBeTruthy();
|
expect(vm.shouldShowMergeControls).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when showing the MWPS button and a pipeline is running that needs to be successful', () => {
|
it('should return true when showing the MWPS button and a pipeline is running that needs to be successful', () => {
|
||||||
vm.mr.isMergeAllowed = false;
|
Vue.set(vm.mr, 'isMergeAllowed', false);
|
||||||
vm.mr.isPipelineActive = true;
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', [MWPS_MERGE_STRATEGY]);
|
||||||
|
|
||||||
expect(vm.shouldShowMergeControls).toBeTruthy();
|
expect(vm.shouldShowMergeControls).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return true when showing the MWPS button but not required for the pipeline to succeed', () => {
|
it('should return true when showing the MWPS button but not required for the pipeline to succeed', () => {
|
||||||
vm.mr.isMergeAllowed = true;
|
Vue.set(vm.mr, 'isMergeAllowed', true);
|
||||||
vm.mr.isPipelineActive = true;
|
Vue.set(vm.mr, 'availableAutoMergeStrategies', [MWPS_MERGE_STRATEGY]);
|
||||||
|
|
||||||
expect(vm.shouldShowMergeControls).toBeTruthy();
|
expect(vm.shouldShowMergeControls).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -325,7 +346,6 @@ describe('ReadyToMerge', () => {
|
||||||
vm.handleMergeButtonClick(true);
|
vm.handleMergeButtonClick(true);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(vm.autoMergeStrategy).toBe('merge_when_pipeline_succeeds');
|
|
||||||
expect(vm.isMakingRequest).toBeTruthy();
|
expect(vm.isMakingRequest).toBeTruthy();
|
||||||
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
|
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
|
||||||
|
|
||||||
|
@ -349,14 +369,13 @@ describe('ReadyToMerge', () => {
|
||||||
vm.handleMergeButtonClick(false, true);
|
vm.handleMergeButtonClick(false, true);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(vm.autoMergeStrategy).toBeUndefined();
|
|
||||||
expect(vm.isMakingRequest).toBeTruthy();
|
expect(vm.isMakingRequest).toBeTruthy();
|
||||||
expect(eventHub.$emit).toHaveBeenCalledWith('FailedToMerge', undefined);
|
expect(eventHub.$emit).toHaveBeenCalledWith('FailedToMerge', undefined);
|
||||||
|
|
||||||
const params = vm.service.merge.calls.argsFor(0)[0];
|
const params = vm.service.merge.calls.argsFor(0)[0];
|
||||||
|
|
||||||
expect(params.should_remove_source_branch).toBeTruthy();
|
expect(params.should_remove_source_branch).toBeTruthy();
|
||||||
expect(params.merge_when_pipeline_succeeds).toBeFalsy();
|
expect(params.auto_merge_strategy).toBeUndefined();
|
||||||
done();
|
done();
|
||||||
}, 333);
|
}, 333);
|
||||||
});
|
});
|
||||||
|
@ -367,14 +386,13 @@ describe('ReadyToMerge', () => {
|
||||||
vm.handleMergeButtonClick();
|
vm.handleMergeButtonClick();
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
expect(vm.autoMergeStrategy).toBeUndefined();
|
|
||||||
expect(vm.isMakingRequest).toBeTruthy();
|
expect(vm.isMakingRequest).toBeTruthy();
|
||||||
expect(vm.initiateMergePolling).toHaveBeenCalled();
|
expect(vm.initiateMergePolling).toHaveBeenCalled();
|
||||||
|
|
||||||
const params = vm.service.merge.calls.argsFor(0)[0];
|
const params = vm.service.merge.calls.argsFor(0)[0];
|
||||||
|
|
||||||
expect(params.should_remove_source_branch).toBeTruthy();
|
expect(params.should_remove_source_branch).toBeTruthy();
|
||||||
expect(params.merge_when_pipeline_succeeds).toBeFalsy();
|
expect(params.auto_merge_strategy).toBeUndefined();
|
||||||
done();
|
done();
|
||||||
}, 333);
|
}, 333);
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,7 +25,6 @@ export default {
|
||||||
},
|
},
|
||||||
merge_status: 'can_be_merged',
|
merge_status: 'can_be_merged',
|
||||||
merge_user_id: null,
|
merge_user_id: null,
|
||||||
merge_when_pipeline_succeeds: false,
|
|
||||||
source_branch: 'daaaa',
|
source_branch: 'daaaa',
|
||||||
source_branch_link: 'daaaa',
|
source_branch_link: 'daaaa',
|
||||||
source_project_id: 19,
|
source_project_id: 19,
|
||||||
|
@ -210,8 +209,7 @@ export default {
|
||||||
source_branch_path: '/root/acets-app/branches/daaaa',
|
source_branch_path: '/root/acets-app/branches/daaaa',
|
||||||
conflict_resolution_ui_path: '/root/acets-app/merge_requests/22/conflicts',
|
conflict_resolution_ui_path: '/root/acets-app/merge_requests/22/conflicts',
|
||||||
remove_wip_path: '/root/acets-app/merge_requests/22/remove_wip',
|
remove_wip_path: '/root/acets-app/merge_requests/22/remove_wip',
|
||||||
cancel_merge_when_pipeline_succeeds_path:
|
cancel_auto_merge_path: '/root/acets-app/merge_requests/22/cancel_auto_merge',
|
||||||
'/root/acets-app/merge_requests/22/cancel_merge_when_pipeline_succeeds',
|
|
||||||
create_issue_to_resolve_discussions_path:
|
create_issue_to_resolve_discussions_path:
|
||||||
'/root/acets-app/issues/new?merge_request_to_resolve_discussions_of=22',
|
'/root/acets-app/issues/new?merge_request_to_resolve_discussions_of=22',
|
||||||
merge_path: '/root/acets-app/merge_requests/22/merge',
|
merge_path: '/root/acets-app/merge_requests/22/merge',
|
||||||
|
@ -237,6 +235,9 @@ export default {
|
||||||
merge_request_pipelines_docs_path: '/help/ci/merge_request_pipelines/index.md',
|
merge_request_pipelines_docs_path: '/help/ci/merge_request_pipelines/index.md',
|
||||||
squash: true,
|
squash: true,
|
||||||
visual_review_app_available: true,
|
visual_review_app_available: true,
|
||||||
|
merge_trains_enabled: true,
|
||||||
|
merge_trains_count: 3,
|
||||||
|
merge_train_index: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mockStore = {
|
export const mockStore = {
|
||||||
|
|
|
@ -82,5 +82,47 @@ describe('MergeRequestStore', () => {
|
||||||
expect(store.isNothingToMergeState).toEqual(false);
|
expect(store.isNothingToMergeState).toEqual(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('mergePipelinesEnabled', () => {
|
||||||
|
it('should set mergePipelinesEnabled = true when merge_pipelines_enabled is true', () => {
|
||||||
|
store.setData({ ...mockData, merge_pipelines_enabled: true });
|
||||||
|
|
||||||
|
expect(store.mergePipelinesEnabled).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set mergePipelinesEnabled = false when merge_pipelines_enabled is not provided', () => {
|
||||||
|
store.setData({ ...mockData, merge_pipelines_enabled: undefined });
|
||||||
|
|
||||||
|
expect(store.mergePipelinesEnabled).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('mergeTrainsCount', () => {
|
||||||
|
it('should set mergeTrainsCount when merge_trains_count is provided', () => {
|
||||||
|
store.setData({ ...mockData, merge_trains_count: 3 });
|
||||||
|
|
||||||
|
expect(store.mergeTrainsCount).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set mergeTrainsCount = 0 when merge_trains_count is not provided', () => {
|
||||||
|
store.setData({ ...mockData, merge_trains_count: undefined });
|
||||||
|
|
||||||
|
expect(store.mergeTrainsCount).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('mergeTrainIndex', () => {
|
||||||
|
it('should set mergeTrainIndex when merge_train_index is provided', () => {
|
||||||
|
store.setData({ ...mockData, merge_train_index: 3 });
|
||||||
|
|
||||||
|
expect(store.mergeTrainIndex).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set mergeTrainIndex when merge_train_index is not provided', () => {
|
||||||
|
store.setData({ ...mockData, merge_train_index: undefined });
|
||||||
|
|
||||||
|
expect(store.mergeTrainIndex).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue