Commit ddd9651c authored by Alexander Turinske's avatar Alexander Turinske

Add download patch functionality for vulnerability

- add ability to download the patch in the split button
- add tests
parent 42fce179
---
title: Add ability to download patch from vulnerability page
merge_request: 32000
author:
type: added
......@@ -2,6 +2,7 @@
import { GlDeprecatedButton, GlLoadingIcon } from '@gitlab/ui';
import Api from 'ee/api';
import axios from '~/lib/utils/axios_utils';
import download from '~/lib/utils/downloader';
import { redirectTo } from '~/lib/utils/url_utility';
import createFlash from '~/flash';
import { s__ } from '~/locale';
......@@ -69,12 +70,21 @@ export default {
buttons.push(HEADER_ACTION_BUTTONS.mergeRequestCreation);
}
if (this.canDownloadPatch) {
buttons.push(HEADER_ACTION_BUTTONS.patchDownload);
}
if (!this.hasIssue) {
buttons.push(HEADER_ACTION_BUTTONS.issueCreation);
}
return buttons;
},
canDownloadPatch() {
return (
this.vulnerability.state !== 'resolved' && !this.vulnerability.hasMr && this.hasRemediation
);
},
hasIssue() {
return Boolean(this.finding.issue_feedback?.issue_iid);
},
......@@ -200,6 +210,9 @@ export default {
);
});
},
downloadPatch() {
download({ fileData: this.finding.remediations[0].diff, fileName: `remediation.patch` });
},
},
};
</script>
......@@ -248,6 +261,7 @@ export default {
class="js-split-button"
@createMergeRequest="createMergeRequest"
@createIssue="createIssue"
@downloadPatch="downloadPatch"
/>
<gl-deprecated-button
v-else-if="actionButtons.length > 0"
......
......@@ -41,6 +41,11 @@ export const HEADER_ACTION_BUTTONS = {
tagline: s__('ciReport|Automatically apply the patch in a new branch'),
action: 'createMergeRequest',
},
patchDownload: {
name: s__('ciReport|Download patch to resolve'),
tagline: s__('ciReport|Download the patch to apply it manually'),
action: 'downloadPatch',
},
};
export const FEEDBACK_TYPES = {
......
......@@ -5,6 +5,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import UsersMockHelper from 'helpers/user_mock_data_helper';
import Api from '~/api';
import axios from '~/lib/utils/axios_utils';
import download from '~/lib/utils/downloader';
import * as urlUtility from '~/lib/utils/url_utility';
import createFlash from '~/flash';
import Header from 'ee/vulnerabilities/components/header.vue';
......@@ -18,6 +19,7 @@ import { FEEDBACK_TYPES, VULNERABILITY_STATE_OBJECTS } from 'ee/vulnerabilities/
const vulnerabilityStateEntries = Object.entries(VULNERABILITY_STATE_OBJECTS);
const mockAxios = new MockAdapter(axios);
jest.mock('~/flash');
jest.mock('~/lib/utils/downloader');
describe('Vulnerability Header', () => {
let wrapper;
......@@ -75,10 +77,11 @@ describe('Vulnerability Header', () => {
const findResolutionAlert = () => wrapper.find(ResolutionAlert);
const findStatusDescription = () => wrapper.find(StatusDescription);
const createWrapper = ({ vulnerability = {}, finding = getFinding({}) }) => {
const createWrapper = ({ vulnerability = {}, finding = getFinding({}), props = {} }) => {
wrapper = shallowMount(Header, {
propsData: {
...dataset,
...props,
initialVulnerability: { ...defaultVulnerability, ...vulnerability },
finding,
},
......@@ -163,9 +166,10 @@ describe('Vulnerability Header', () => {
});
expect(findSplitButton().exists()).toBe(true);
const buttons = findSplitButton().props('buttons');
expect(buttons).toHaveLength(2);
expect(buttons).toHaveLength(3);
expect(buttons[0].name).toBe('Resolve with merge request');
expect(buttons[1].name).toBe('Create issue');
expect(buttons[1].name).toBe('Download patch to resolve');
expect(buttons[2].name).toBe('Create issue');
});
it('does not render the split button if there is only one action', () => {
......@@ -282,6 +286,29 @@ describe('Vulnerability Header', () => {
});
});
});
describe('can download download patch', () => {
beforeEach(() => {
createWrapper({
finding: getFinding({ shouldShowMergeRequestButton: true }),
props: { createMrUrl: '' },
});
});
it('only renders the download patch button', () => {
expect(findGlDeprecatedButton().exists()).toBe(true);
expect(findGlDeprecatedButton().text()).toBe('Download patch to resolve');
});
it('emits downloadPatch when download patch button is clicked', () => {
const glDeprecatedButton = findGlDeprecatedButton();
expect(glDeprecatedButton.exists()).toBe(true);
glDeprecatedButton.vm.$emit('click');
return wrapper.vm.$nextTick().then(() => {
expect(download).toHaveBeenCalledWith({ fileData: diff, fileName: `remediation.patch` });
});
});
});
});
describe('state badge', () => {
......
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