Commit 4841ece4 authored by Phil Hughes's avatar Phil Hughes

Created a new merge checks failed component

This new component will handle all cases where a merge check
fails.

Closes https://gitlab.com/gitlab-org/gitlab/-/issues/324164/
parent 122dce2a
<script>
import { GlButton } from '@gitlab/ui';
import { s__ } from '~/locale';
import notesEventHub from '~/notes/event_hub';
import StatusIcon from '../mr_widget_status_icon.vue';
export default {
i18n: {
pipelineFailed: s__(
'mrWidget|The pipeline for this merge request did not complete. Push a new commit to fix the failure.',
),
approvalNeeded: s__('mrWidget|You can only merge once this merge request is approved.'),
unresolvedDiscussions: s__('mrWidget|Merge blocked: all threads must be resolved.'),
},
components: {
StatusIcon,
GlButton,
},
props: {
mr: {
type: Object,
required: true,
},
},
computed: {
failedText() {
if (this.mr.isPipelineFailed) {
return this.$options.i18n.pipelineFailed;
} else if (this.mr.approvals && !this.mr.isApproved) {
return this.$options.i18n.approvalNeeded;
} else if (this.mr.hasMergeableDiscussionsState) {
return this.$options.i18n.unresolvedDiscussions;
}
return null;
},
},
methods: {
jumpToFirstUnresolvedDiscussion() {
notesEventHub.$emit('jumpToFirstUnresolvedDiscussion');
},
},
};
</script>
<template>
<div class="mr-widget-body media gl-flex-wrap">
<status-icon status="warning" />
<p class="media-body gl-m-0! gl-font-weight-bold gl-text-black-normal!">
{{ failedText }}
<template v-if="failedText == $options.i18n.unresolvedDiscussions">
<gl-button
class="gl-ml-3"
size="small"
variant="confirm"
data-testid="jumpToUnresolved"
@click="jumpToFirstUnresolvedDiscussion"
>
{{ s__('mrWidget|Jump to first unresolved thread') }}
</gl-button>
<gl-button
v-if="mr.createIssueToResolveDiscussionsPath"
:href="mr.createIssueToResolveDiscussionsPath"
class="gl-ml-3"
size="small"
variant="confirm"
category="secondary"
data-testid="resolveIssue"
>
{{ s__('mrWidget|Create issue to resolve all threads') }}
</gl-button>
</template>
</p>
</div>
</template>
......@@ -89,6 +89,7 @@ export default {
import('../reports/accessibility_report/grouped_accessibility_reports_app.vue'),
MrWidgetApprovals,
SecurityReportsApp: () => import('~/vue_shared/security_reports/security_reports_app.vue'),
MergeChecksFailed: () => import('./components/states/merge_checks_failed.vue'),
},
apollo: {
state: {
......
import { stateKey } from './state_maps';
export default function deviseState() {
if (this.projectArchived) {
if (this.hasMergeChecksFailed) {
return stateKey.mergeChecksFailed;
} else if (this.projectArchived) {
return stateKey.archived;
} else if (this.branchMissing) {
return stateKey.missingBranch;
......
......@@ -347,4 +347,13 @@ export default class MergeRequestStore {
this.approvals = data;
this.isApproved = data.approved || false;
}
get hasMergeChecksFailed() {
if (!window.gon?.features?.restructuredMrWidget) return false;
return (
this.hasMergeableDiscussionsState ||
(this.onlyAllowMergeIfPipelineSucceeds && this.isPipelineFailed)
);
}
}
......@@ -18,6 +18,7 @@ const stateToComponentMap = {
autoMergeFailed: 'mr-widget-auto-merge-failed',
shaMismatch: 'sha-mismatch',
rebase: 'mr-widget-rebase',
mergeChecksFailed: 'mergeChecksFailed',
};
const statesToShowHelpWidget = [
......@@ -50,6 +51,7 @@ export const stateKey = {
readyToMerge: 'readyToMerge',
rebase: 'rebase',
merged: 'merged',
mergeChecksFailed: 'mergeChecksFailed',
};
export default {
......
......@@ -89,6 +89,14 @@ export default class MergeRequestStore extends CEMergeRequestStore {
this.approvalRules = mapApprovalRulesResponse(data.rules, this.approvals);
}
get hasMergeChecksFailed() {
if (!window.gon?.features?.restructuredMrWidget) return false;
if (this.hasApprovalsAvailable) return !this.isApproved;
return super.hasMergeChecksFailed;
}
initBrowserPerformanceReport(data) {
this.browserPerformance = data.browser_performance;
this.browserPerformanceMetrics = {
......
......@@ -40347,6 +40347,9 @@ msgstr ""
msgid "mrWidget|The pipeline for this merge request did not complete. Push a new commit to fix the failure, or check the %{linkStart}troubleshooting documentation%{linkEnd} to see other possible actions."
msgstr ""
msgid "mrWidget|The pipeline for this merge request did not complete. Push a new commit to fix the failure."
msgstr ""
msgid "mrWidget|The source branch has been deleted"
msgstr ""
......@@ -40389,6 +40392,9 @@ msgstr ""
msgid "mrWidget|You can merge after removing denied licenses"
msgstr ""
msgid "mrWidget|You can only merge once this merge request is approved."
msgstr ""
msgid "mrWidget|Your password"
msgstr ""
......
import { shallowMount } from '@vue/test-utils';
import MergeChecksFailed from '~/vue_merge_request_widget/components/states/merge_checks_failed.vue';
let wrapper;
function factory(propsData = {}) {
wrapper = shallowMount(MergeChecksFailed, {
propsData,
});
}
describe('Merge request widget merge checks failed state component', () => {
afterEach(() => {
wrapper.destroy();
});
it.each`
mrState | displayText
${{ isPipelineFailed: true }} | ${'pipelineFailed'}
${{ approvals: true, isApproved: false }} | ${'approvalNeeded'}
${{ hasMergeableDiscussionsState: true }} | ${'unresolvedDiscussions'}
`('display $displayText text for $mrState', ({ mrState, displayText }) => {
factory({ mr: mrState });
expect(wrapper.text()).toContain(MergeChecksFailed.i18n[displayText]);
});
describe('unresolved discussions', () => {
it('renders jump to button', () => {
factory({ mr: { hasMergeableDiscussionsState: true } });
expect(wrapper.find('[data-testid="jumpToUnresolved"]').exists()).toBe(true);
});
it('renders resolve thread button', () => {
factory({
mr: {
hasMergeableDiscussionsState: true,
createIssueToResolveDiscussionsPath: 'https://gitlab.com',
},
});
expect(wrapper.find('[data-testid="resolveIssue"]').exists()).toBe(true);
expect(wrapper.find('[data-testid="resolveIssue"]').attributes('href')).toBe(
'https://gitlab.com',
);
});
});
});
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