Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
28ff61b1
Commit
28ff61b1
authored
Aug 25, 2021
by
Payton Burdette
Committed by
Phil Hughes
Aug 25, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add confirmation modal when pipeline failed [RUN AS-IF-FOSS]
parent
3e840e6e
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
217 additions
and
3 deletions
+217
-3
app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
...merge_request_widget/components/states/ready_to_merge.vue
+17
-2
app/assets/javascripts/vue_merge_request_widget/constants.js
app/assets/javascripts/vue_merge_request_widget/constants.js
+2
-0
app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js
...scripts/vue_merge_request_widget/mixins/ready_to_merge.js
+8
-0
ee/app/assets/javascripts/vue_merge_request_widget/components/merge_train_failed_pipeline_confirmation_dialog.vue
...nents/merge_train_failed_pipeline_confirmation_dialog.vue
+60
-0
ee/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js
...scripts/vue_merge_request_widget/mixins/ready_to_merge.js
+16
-1
ee/spec/frontend/vue_mr_widget/components/merge_train_failed_pipeline_confirmation_dialog_spec.js
...s/merge_train_failed_pipeline_confirmation_dialog_spec.js
+78
-0
ee/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
...widget/components/states/mr_widget_ready_to_merge_spec.js
+30
-0
locale/gitlab.pot
locale/gitlab.pot
+6
-0
No files found.
app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue
View file @
28ff61b1
...
...
@@ -28,6 +28,7 @@ import {
CONFIRM
,
WARNING
,
MT_MERGE_STRATEGY
,
PIPELINE_FAILED_STATE
,
}
from
'
../../constants
'
;
import
eventHub
from
'
../../event_hub
'
;
import
mergeRequestQueryVariablesMixin
from
'
../../mixins/merge_request_query_variables
'
;
...
...
@@ -39,7 +40,6 @@ import CommitsHeader from './commits_header.vue';
import
SquashBeforeMerge
from
'
./squash_before_merge.vue
'
;
const
PIPELINE_RUNNING_STATE
=
'
running
'
;
const
PIPELINE_FAILED_STATE
=
'
failed
'
;
const
PIPELINE_PENDING_STATE
=
'
pending
'
;
const
PIPELINE_SUCCESS_STATE
=
'
success
'
;
...
...
@@ -105,6 +105,10 @@ export default {
import
(
'
ee_component/vue_merge_request_widget/components/merge_immediately_confirmation_dialog.vue
'
),
MergeTrainFailedPipelineConfirmationDialog
:
()
=>
import
(
'
ee_component/vue_merge_request_widget/components/merge_train_failed_pipeline_confirmation_dialog.vue
'
),
},
directives
:
{
GlTooltip
:
GlTooltipDirective
,
...
...
@@ -125,6 +129,7 @@ export default {
squashBeforeMerge
:
this
.
mr
.
squashIsSelected
,
isSquashReadOnly
:
this
.
mr
.
squashIsReadonly
,
squashCommitMessage
:
this
.
mr
.
squashCommitMessage
,
isPipelineFailedModalVisible
:
false
,
};
},
computed
:
{
...
...
@@ -327,7 +332,12 @@ export default {
:
this
.
mr
.
commitMessageWithDescription
;
this
.
commitMessage
=
includeDescription
?
commitMessageWithDescription
:
commitMessage
;
},
handleMergeButtonClick
(
useAutoMerge
,
mergeImmediately
=
false
)
{
handleMergeButtonClick
(
useAutoMerge
,
mergeImmediately
=
false
,
confirmationClicked
=
false
)
{
if
(
this
.
showFailedPipelineModal
&&
!
confirmationClicked
)
{
this
.
isPipelineFailedModalVisible
=
true
;
return
;
}
if
(
mergeImmediately
)
{
this
.
isMergingImmediately
=
true
;
}
...
...
@@ -522,6 +532,11 @@ export default {
@
mergeImmediately=
"onMergeImmediatelyConfirmation"
/>
</gl-dropdown>
<merge-train-failed-pipeline-confirmation-dialog
:visible=
"isPipelineFailedModalVisible"
@
startMergeTrain=
"onStartMergeTrainConfirmation"
@
cancel=
"isPipelineFailedModalVisible = false"
/>
</gl-button-group>
<div
v-if=
"shouldShowMergeControls"
...
...
app/assets/javascripts/vue_merge_request_widget/constants.js
View file @
28ff61b1
...
...
@@ -10,6 +10,8 @@ export const MWPS_MERGE_STRATEGY = 'merge_when_pipeline_succeeds';
export
const
MTWPS_MERGE_STRATEGY
=
'
add_to_merge_train_when_pipeline_succeeds
'
;
export
const
MT_MERGE_STRATEGY
=
'
merge_train
'
;
export
const
PIPELINE_FAILED_STATE
=
'
failed
'
;
export
const
AUTO_MERGE_STRATEGIES
=
[
MWPS_MERGE_STRATEGY
,
MTWPS_MERGE_STRATEGY
,
MT_MERGE_STRATEGY
];
// SP - "Suggest Pipelines"
...
...
app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js
View file @
28ff61b1
...
...
@@ -38,5 +38,13 @@ export default {
pipelineId
()
{
return
this
.
pipeline
.
id
;
},
showFailedPipelineModal
()
{
return
false
;
},
},
methods
:
{
onStartMergeTrainConfirmation
()
{
return
false
;
},
},
};
ee/app/assets/javascripts/vue_merge_request_widget/components/merge_train_failed_pipeline_confirmation_dialog.vue
0 → 100644
View file @
28ff61b1
<
script
>
import
{
GlModal
,
GlButton
}
from
'
@gitlab/ui
'
;
import
{
__
}
from
'
~/locale
'
;
export
default
{
name
:
'
MergeTrainFailedPipelineConfirmationDialog
'
,
i18n
:
{
title
:
__
(
'
Start merge train
'
),
cancel
:
__
(
'
Cancel
'
),
info
:
__
(
'
The latest pipeline for this merge request has failed.
'
),
confirmation
:
__
(
'
Are you sure you want to attempt to merge?
'
),
},
components
:
{
GlModal
,
GlButton
,
},
props
:
{
visible
:
{
type
:
Boolean
,
required
:
true
,
},
},
methods
:
{
hide
()
{
this
.
$refs
.
modal
.
hide
();
},
cancel
()
{
this
.
hide
();
this
.
$emit
(
'
cancel
'
);
},
focusCancelButton
()
{
this
.
$refs
.
cancelButton
.
$el
.
focus
();
},
startMergeTrain
()
{
this
.
$emit
(
'
startMergeTrain
'
);
this
.
hide
();
},
},
};
</
script
>
<
template
>
<gl-modal
ref=
"modal"
modal-id=
"merge-train-failed-pipeline-confirmation-dialog"
size=
"sm"
:title=
"$options.i18n.title"
:visible=
"visible"
@
shown=
"focusCancelButton"
@
hide=
"$emit('cancel')"
>
<p>
{{
$options
.
i18n
.
info
}}
</p>
<p>
{{
$options
.
i18n
.
confirmation
}}
</p>
<template
#modal-footer
>
<gl-button
ref=
"cancelButton"
@
click=
"cancel"
>
{{
$options
.
i18n
.
cancel
}}
</gl-button>
<gl-button
variant=
"danger"
data-testid=
"start-merge-train"
@
click=
"startMergeTrain"
>
{{
$options
.
i18n
.
title
}}
</gl-button>
</
template
>
</gl-modal>
</template>
ee/app/assets/javascripts/vue_merge_request_widget/mixins/ready_to_merge.js
View file @
28ff61b1
import
{
isNumber
,
isString
}
from
'
lodash
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
MTWPS_MERGE_STRATEGY
,
MT_MERGE_STRATEGY
}
from
'
~/vue_merge_request_widget/constants
'
;
import
{
MTWPS_MERGE_STRATEGY
,
MT_MERGE_STRATEGY
,
PIPELINE_FAILED_STATE
,
}
from
'
~/vue_merge_request_widget/constants
'
;
import
base
from
'
~/vue_merge_request_widget/mixins/ready_to_merge
'
;
export
const
MERGE_DISABLED_TEXT_UNAPPROVED
=
__
(
...
...
@@ -76,5 +80,16 @@ export default {
isMergeImmediatelyDangerous
()
{
return
[
MT_MERGE_STRATEGY
,
MTWPS_MERGE_STRATEGY
].
includes
(
this
.
preferredAutoMergeStrategy
);
},
showFailedPipelineModal
()
{
const
pipelineFailed
=
this
.
status
===
PIPELINE_FAILED_STATE
||
this
.
isPipelineFailed
;
const
mergeStrateyMergeTrain
=
this
.
preferredAutoMergeStrategy
===
MT_MERGE_STRATEGY
;
return
pipelineFailed
&&
mergeStrateyMergeTrain
;
},
},
methods
:
{
onStartMergeTrainConfirmation
()
{
this
.
handleMergeButtonClick
(
this
.
isAutoMergeAvailable
,
false
,
true
);
},
},
};
ee/spec/frontend/vue_mr_widget/components/merge_train_failed_pipeline_confirmation_dialog_spec.js
0 → 100644
View file @
28ff61b1
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
MergeTrainFailedPipelineConfirmationDialog
from
'
ee/vue_merge_request_widget/components/merge_train_failed_pipeline_confirmation_dialog.vue
'
;
import
{
trimText
}
from
'
helpers/text_helper
'
;
describe
(
'
MergeTrainFailedPipelineConfirmationDialog
'
,
()
=>
{
let
wrapper
;
const
GlModal
=
{
template
:
`
<div>
<slot></slot>
<slot name="modal-footer"></slot>
</div>
`
,
methods
:
{
hide
:
jest
.
fn
(),
},
};
const
createComponent
=
()
=>
{
wrapper
=
shallowMount
(
MergeTrainFailedPipelineConfirmationDialog
,
{
propsData
:
{
visible
:
true
,
},
stubs
:
{
GlModal
,
},
attachTo
:
document
.
body
,
});
};
const
findModal
=
()
=>
wrapper
.
find
(
GlModal
);
const
findStartMergeTrainBtn
=
()
=>
wrapper
.
find
(
'
[data-testid="start-merge-train"]
'
);
const
findCancelBtn
=
()
=>
wrapper
.
find
({
ref
:
'
cancelButton
'
});
beforeEach
(()
=>
{
createComponent
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
it
(
'
should render informational text explaining why merging immediately can be dangerous
'
,
()
=>
{
expect
(
trimText
(
wrapper
.
text
())).
toContain
(
'
The latest pipeline for this merge request has failed. Are you sure you want to attempt to merge?
'
,
);
});
it
(
'
should emit the startMergeTrain event
'
,
()
=>
{
findStartMergeTrainBtn
().
vm
.
$emit
(
'
click
'
);
expect
(
wrapper
.
emitted
(
'
startMergeTrain
'
)).
toBeTruthy
();
});
it
(
'
when the cancel button is clicked should emit cancel and call hide
'
,
()
=>
{
jest
.
spyOn
(
findModal
().
vm
,
'
hide
'
);
findCancelBtn
().
vm
.
$emit
(
'
click
'
);
expect
(
wrapper
.
emitted
(
'
cancel
'
)).
toBeTruthy
();
expect
(
findModal
().
vm
.
hide
).
toHaveBeenCalled
();
});
it
(
'
should emit cancel when the hide event is emitted
'
,
()
=>
{
findModal
().
vm
.
$emit
(
'
hide
'
);
expect
(
wrapper
.
emitted
(
'
cancel
'
)).
toBeTruthy
();
});
it
(
'
when modal is shown it will focus the cancel button
'
,
()
=>
{
findCancelBtn
().
element
.
focus
=
jest
.
fn
();
findModal
().
vm
.
$emit
(
'
shown
'
);
expect
(
findCancelBtn
().
element
.
focus
).
toHaveBeenCalled
();
});
});
ee/spec/frontend/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js
View file @
28ff61b1
import
{
GlLink
,
GlSprintf
}
from
'
@gitlab/ui
'
;
import
{
mount
,
shallowMount
}
from
'
@vue/test-utils
'
;
import
MergeImmediatelyConfirmationDialog
from
'
ee/vue_merge_request_widget/components/merge_immediately_confirmation_dialog.vue
'
;
import
MergeTrainFailedPipelineConfirmationDialog
from
'
ee/vue_merge_request_widget/components/merge_train_failed_pipeline_confirmation_dialog.vue
'
;
import
MergeTrainHelperText
from
'
ee/vue_merge_request_widget/components/merge_train_helper_text.vue
'
;
import
{
MERGE_DISABLED_TEXT_UNAPPROVED
}
from
'
ee/vue_merge_request_widget/mixins/ready_to_merge
'
;
import
ReadyToMerge
from
'
~/vue_merge_request_widget/components/states/ready_to_merge.vue
'
;
...
...
@@ -69,6 +70,7 @@ describe('ReadyToMerge', () => {
MergeTrainHelperText
,
GlSprintf
,
GlLink
,
MergeTrainFailedPipelineConfirmationDialog
,
},
});
...
...
@@ -88,6 +90,8 @@ describe('ReadyToMerge', () => {
findMergeTrainHelperText
().
find
(
'
[data-testid="documentation-link"]
'
);
const
findFailedPipelineMergeTrainText
=
()
=>
wrapper
.
find
(
'
[data-testid="failed-pipeline-merge-train-text"]
'
);
const
findMergeTrainFailedPipelineConfirmationDialog
=
()
=>
wrapper
.
findComponent
(
MergeTrainFailedPipelineConfirmationDialog
);
afterEach
(()
=>
{
if
(
wrapper
?.
destroy
)
{
...
...
@@ -323,6 +327,32 @@ describe('ReadyToMerge', () => {
});
});
describe
(
'
merge train failed confirmation dialog
'
,
()
=>
{
it
.
each
`
mergeStrategy | isPipelineFailed | isVisible
${
MT_MERGE_STRATEGY
}
|
${
true
}
|
${
true
}
${
MT_MERGE_STRATEGY
}
|
${
false
}
|
${
false
}
${
MTWPS_MERGE_STRATEGY
}
|
${
true
}
|
${
false
}
${
MWPS_MERGE_STRATEGY
}
|
${
true
}
|
${
false
}
`
(
'
with merge stragtegy $mergeStrategy and pipeline failed status of $isPipelineFailed we should show the modal: $isVisible
'
,
async
({
mergeStrategy
,
isPipelineFailed
,
isVisible
})
=>
{
factory
({
preferredAutoMergeStrategy
:
mergeStrategy
,
isPipelineFailed
});
const
modalConfirmation
=
findMergeTrainFailedPipelineConfirmationDialog
();
if
(
!
isVisible
)
{
// need to mock if we don't show modal
// to prevent internals from being invoked
vm
.
handleMergeButtonClick
=
jest
.
fn
();
}
await
findMergeButton
().
vm
.
$emit
(
'
click
'
);
expect
(
modalConfirmation
.
props
(
'
visible
'
)).
toBe
(
isVisible
);
},
);
});
describe
(
'
merge immediately warning dialog
'
,
()
=>
{
let
dialog
;
...
...
locale/gitlab.pot
View file @
28ff61b1
...
...
@@ -4379,6 +4379,9 @@ msgstr ""
msgid "Are you sure you want to %{action} %{name}?"
msgstr ""
msgid "Are you sure you want to attempt to merge?"
msgstr ""
msgid "Are you sure you want to cancel editing this comment?"
msgstr ""
...
...
@@ -33322,6 +33325,9 @@ msgstr ""
msgid "The latest pipeline for this merge request did not complete successfully."
msgstr ""
msgid "The latest pipeline for this merge request has failed."
msgstr ""
msgid "The license key is invalid. Make sure it is exactly as you received it from GitLab Inc."
msgstr ""
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment