summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_merge_request_widget
diff options
context:
space:
mode:
authorNathan Friend <nathan@gitlab.com>2019-06-11 09:19:22 -0500
committerNathan Friend <nathan@gitlab.com>2019-06-11 09:27:51 -0500
commit35ae9d8a7449ebe4b5c1878825bcb931a82e7a59 (patch)
tree4e5c698fbcce2c9bffa0a1cdfe1ce449f750ad05 /app/assets/javascripts/vue_merge_request_widget
parentfc27c93e4b060db069f1651d1395d59e121595f7 (diff)
downloadgitlab-ce-35ae9d8a7449ebe4b5c1878825bcb931a82e7a59.tar.gz
Add merge train support to MR merge button (CE)9186-implement-atmtwps-state-to-mr-widget
This commit updates the merge request widget's "Merge" button to support merge trains.
Diffstat (limited to 'app/assets/javascripts/vue_merge_request_widget')
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue (renamed from app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue)16
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue47
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/constants.js10
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mixins/auto_merge.js15
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js6
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js22
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js2
8 files changed, 85 insertions, 37 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
index 88e1ccbaf35..5958c2cf87e 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue
@@ -1,15 +1,19 @@
<script>
+import _ from 'underscore';
+import autoMergeMixin from 'ee_else_ce/vue_merge_request_widget/mixins/auto_merge';
import Flash from '../../../flash';
import statusIcon from '../mr_widget_status_icon.vue';
import MrWidgetAuthor from '../../components/mr_widget_author.vue';
import eventHub from '../../event_hub';
+import { AUTO_MERGE_STRATEGIES } from '../../constants';
export default {
- name: 'MRWidgetMergeWhenPipelineSucceeds',
+ name: 'MRWidgetAutoMergeEnabled',
components: {
MrWidgetAuthor,
statusIcon,
},
+ mixins: [autoMergeMixin],
props: {
mr: {
type: Object,
@@ -57,7 +61,7 @@ export default {
removeSourceBranch() {
const options = {
sha: this.mr.sha,
- auto_merge_strategy: 'merge_when_pipeline_succeeds',
+ auto_merge_strategy: this.mr.autoMergeStrategy,
should_remove_source_branch: true,
};
@@ -66,7 +70,7 @@ export default {
.merge(options)
.then(res => res.data)
.then(data => {
- if (data.status === 'merge_when_pipeline_succeeds') {
+ if (_.includes(AUTO_MERGE_STRATEGIES, data.status)) {
eventHub.$emit('MRWidgetUpdateRequested');
}
})
@@ -84,9 +88,9 @@ export default {
<div class="media-body">
<h4 class="d-flex align-items-start">
<span class="append-right-10">
- {{ s__('mrWidget|Set by') }}
+ <span class="js-status-text-before-author">{{ statusTextBeforeAuthor }}</span>
<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>
<a
v-if="mr.canCancelAutomaticMerge"
@@ -97,7 +101,7 @@ export default {
@click.prevent="cancelAutomaticMerge"
>
<i v-if="isCancellingAutoMerge" class="fa fa-spinner fa-spin" aria-hidden="true"> </i>
- {{ s__('mrWidget|Cancel automatic merge') }}
+ {{ cancelButtonText }}
</a>
</h4>
<section class="mr-info-list">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
index 615d59a7b8e..ca1b4a57717 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
@@ -1,4 +1,5 @@
<script>
+import _ from 'underscore';
import successSvg from 'icons/_icon_status_success.svg';
import warningSvg from 'icons/_icon_status_warning.svg';
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 CommitEdit from './commit_edit.vue';
import CommitMessageDropdown from './commit_message_dropdown.vue';
+import { AUTO_MERGE_STRATEGIES } from '../../constants';
export default {
name: 'ReadyToMerge',
@@ -30,8 +32,6 @@ export default {
data() {
return {
removeSourceBranch: this.mr.shouldRemoveSourceBranch,
- mergeWhenBuildSucceeds: false,
- autoMergeStrategy: undefined,
isMakingRequest: false,
isMergingImmediately: false,
commitMessage: this.mr.commitMessage,
@@ -42,18 +42,18 @@ export default {
};
},
computed: {
- shouldShowAutoMergeText() {
- return this.mr.isPipelineActive;
+ isAutoMergeAvailable() {
+ return !_.isEmpty(this.mr.availableAutoMergeStrategies);
},
status() {
- const { pipeline, isPipelineActive, isPipelineFailed, hasCI, ciStatus } = this.mr;
+ const { pipeline, isPipelineFailed, hasCI, ciStatus } = this.mr;
if (hasCI && !ciStatus) {
return 'failed';
+ } else if (this.isAutoMergeAvailable) {
+ return 'pending';
} else if (!pipeline) {
return 'success';
- } else if (isPipelineActive) {
- return 'pending';
} else if (isPipelineFailed) {
return 'failed';
}
@@ -87,14 +87,14 @@ export default {
mergeButtonText() {
if (this.isMergingImmediately) {
return __('Merge in progress');
- } else if (this.shouldShowAutoMergeText) {
- return __('Merge when pipeline succeeds');
+ } else if (this.isAutoMergeAvailable) {
+ return this.autoMergeText;
}
- return 'Merge';
+ return __('Merge');
},
shouldShowMergeOptionsDropdown() {
- return this.mr.isPipelineActive && !this.mr.onlyAllowMergeIfPipelineSucceeds;
+ return this.isAutoMergeAvailable && !this.mr.onlyAllowMergeIfPipelineSucceeds;
},
isRemoveSourceBranchButtonDisabled() {
return this.isMergeButtonDisabled;
@@ -104,7 +104,7 @@ export default {
return enableSquashBeforeMerge && commitsCount > 1;
},
shouldShowMergeControls() {
- return this.mr.isMergeAllowed || this.shouldShowAutoMergeText;
+ return this.mr.isMergeAllowed || this.isAutoMergeAvailable;
},
shouldShowSquashEdit() {
return this.squashBeforeMerge && this.shouldShowSquashBeforeMerge;
@@ -118,20 +118,15 @@ export default {
const { commitMessageWithDescription, commitMessage } = this.mr;
this.commitMessage = includeDescription ? commitMessageWithDescription : commitMessage;
},
- handleMergeButtonClick(mergeWhenBuildSucceeds, mergeImmediately) {
- // TODO: Remove no-param-reassign
- if (mergeWhenBuildSucceeds === undefined) {
- mergeWhenBuildSucceeds = this.mr.isPipelineActive; // eslint-disable-line no-param-reassign
- } else if (mergeImmediately) {
+ handleMergeButtonClick(useAutoMerge, mergeImmediately = false) {
+ if (mergeImmediately) {
this.isMergingImmediately = true;
}
- this.autoMergeStrategy = mergeWhenBuildSucceeds ? 'merge_when_pipeline_succeeds' : undefined;
-
const options = {
sha: this.mr.sha,
commit_message: this.commitMessage,
- auto_merge_strategy: this.autoMergeStrategy,
+ auto_merge_strategy: useAutoMerge ? this.mr.preferredAutoMergeStrategy : undefined,
should_remove_source_branch: this.removeSourceBranch === true,
squash: this.squashBeforeMerge,
squash_commit_message: this.squashCommitMessage,
@@ -144,7 +139,7 @@ export default {
.then(data => {
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');
} else if (data.status === 'success') {
this.initiateMergePolling();
@@ -242,13 +237,13 @@ export default {
:class="mergeButtonClass"
type="button"
class="qa-merge-button"
- @click="handleMergeButtonClick()"
+ @click="handleMergeButtonClick(isAutoMergeAvailable)"
>
<i v-if="isMakingRequest" class="fa fa-spinner fa-spin" aria-hidden="true"></i>
{{ mergeButtonText }}
</button>
<button
- v-if="shouldShowMergeOptionsDropdown"
+ v-if="isAutoMergeAvailable"
:disabled="isMergeButtonDisabled"
type="button"
class="btn btn-sm btn-info dropdown-toggle js-merge-moment"
@@ -264,15 +259,13 @@ export default {
>
<li>
<a
- class="merge_when_pipeline_succeeds qa-merge-when-pipeline-succeeds-option"
+ class="auto_merge_enabled qa-merge-when-pipeline-succeeds-option"
href="#"
@click.prevent="handleMergeButtonClick(true)"
>
<span class="media">
<span class="merge-opt-icon" aria-hidden="true" v-html="successSvg"></span>
- <span class="media-body merge-opt-title">{{
- __('Merge when pipeline succeeds')
- }}</span>
+ <span class="media-body merge-opt-title">{{ autoMergeText }}</span>
</span>
</a>
</li>
diff --git a/app/assets/javascripts/vue_merge_request_widget/constants.js b/app/assets/javascripts/vue_merge_request_widget/constants.js
index 0a29d55fbd6..3e65bdf0cb0 100644
--- a/app/assets/javascripts/vue_merge_request_widget/constants.js
+++ b/app/assets/javascripts/vue_merge_request_widget/constants.js
@@ -3,3 +3,13 @@ export const DANGER = 'danger';
export const WARNING_MESSAGE_CLASS = 'warning_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,
+];
diff --git a/app/assets/javascripts/vue_merge_request_widget/mixins/auto_merge.js b/app/assets/javascripts/vue_merge_request_widget/mixins/auto_merge.js
new file mode 100644
index 00000000000..23e140623cc
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/mixins/auto_merge.js
@@ -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');
+ },
+ },
+};
diff --git a/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js
index b2e64506472..116d537c463 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js
+++ b/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js
@@ -1,3 +1,5 @@
+import { __ } from '~/locale';
+
export default {
computed: {
isMergeButtonDisabled() {
@@ -9,5 +11,9 @@ export default {
this.mr.preventMerge,
);
},
+ autoMergeText() {
+ // MWPS is currently the only auto merge strategy available in CE
+ return __('Merge when pipeline succeeds');
+ },
},
};
diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
index d02bb2f341d..a39c4911dce 100644
--- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue
@@ -29,7 +29,7 @@ import UnresolvedDiscussionsState from './components/states/unresolved_discussio
import PipelineBlockedState from './components/states/mr_widget_pipeline_blocked.vue';
import PipelineFailedState from './components/states/pipeline_failed.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 CheckingState from './components/states/mr_widget_checking.vue';
import eventHub from './event_hub';
@@ -64,7 +64,7 @@ export default {
'mr-widget-unresolved-discussions': UnresolvedDiscussionsState,
'mr-widget-pipeline-blocked': PipelineBlockedState,
'mr-widget-pipeline-failed': PipelineFailedState,
- 'mr-widget-merge-when-pipeline-succeeds': MergeWhenPipelineSucceedsState,
+ MrWidgetAutoMergeEnabled,
'mr-widget-auto-merge-failed': AutoMergeFailed,
'mr-widget-rebase': RebaseState,
SourceBranchRemovalStatus,
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 32badb0fb08..bfa3e7f4a59 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
@@ -1,7 +1,9 @@
import Timeago from 'timeago.js';
+import _ from 'underscore';
import getStateKey from 'ee_else_ce/vue_merge_request_widget/stores/get_state_key';
import { stateKey } from './state_maps';
import { formatDate } from '../../lib/utils/datetime_utility';
+import { ATMTWPS_MERGE_STRATEGY, MT_MERGE_STRATEGY, MWPS_MERGE_STRATEGY } from '../constants';
export default class MergeRequestStore {
constructor(data) {
@@ -77,6 +79,10 @@ export default class MergeRequestStore {
this.onlyAllowMergeIfPipelineSucceeds = data.only_allow_merge_if_pipeline_succeeds || false;
this.autoMergeEnabled = Boolean(data.auto_merge_enabled);
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.ffOnlyEnabled = data.ff_only_enabled;
this.shouldBeRebased = Boolean(data.should_be_rebased);
@@ -104,7 +110,9 @@ export default class MergeRequestStore {
this.sourceProjectFullPath = data.source_project_full_path;
this.sourceProjectId = data.source_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
this.canCherryPickInCurrentMR = currentUser.can_cherry_pick_on_current_merge_request || false;
@@ -204,4 +212,16 @@ export default class MergeRequestStore {
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;
+ }
}
diff --git a/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js b/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js
index 48bc6a867f4..28507bba3e5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js
+++ b/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js
@@ -13,7 +13,7 @@ const stateToComponentMap = {
unresolvedDiscussions: 'mr-widget-unresolved-discussions',
pipelineBlocked: 'mr-widget-pipeline-blocked',
pipelineFailed: 'mr-widget-pipeline-failed',
- autoMergeEnabled: 'mr-widget-merge-when-pipeline-succeeds',
+ autoMergeEnabled: 'mr-widget-auto-merge-enabled',
failedToMerge: 'mr-widget-failed-to-merge',
autoMergeFailed: 'mr-widget-auto-merge-failed',
shaMismatch: 'sha-mismatch',