Commit 9d7836ba authored by samdbeckham's avatar samdbeckham

Adds source branch support to auto MRs

- Updates merge_request_url to merge_request_path after a backend change
- Adds target_branch to merge request creation request
- Adds sourceBranch to the security reports so we know what to target
parent 082d19bf
...@@ -15,6 +15,7 @@ export default () => { ...@@ -15,6 +15,7 @@ export default () => {
const datasetOptions = securityTab.dataset; const datasetOptions = securityTab.dataset;
const { const {
headBlobPath, headBlobPath,
sourceBranch,
sastHeadPath, sastHeadPath,
sastHelpPath, sastHelpPath,
dependencyScanningHeadPath, dependencyScanningHeadPath,
...@@ -44,6 +45,7 @@ export default () => { ...@@ -44,6 +45,7 @@ export default () => {
return createElement('security-report-app', { return createElement('security-report-app', {
props: { props: {
headBlobPath, headBlobPath,
sourceBranch,
sastHeadPath, sastHeadPath,
sastHelpPath, sastHelpPath,
dependencyScanningHeadPath, dependencyScanningHeadPath,
......
...@@ -177,7 +177,7 @@ export default { ...@@ -177,7 +177,7 @@ export default {
}, },
[types.RECEIVE_CREATE_MERGE_REQUEST_SUCCESS](state, payload) { [types.RECEIVE_CREATE_MERGE_REQUEST_SUCCESS](state, payload) {
// We don't cancel the loading state here because we're navigating away from the page // We don't cancel the loading state here because we're navigating away from the page
visitUrl(payload.merge_request_url); visitUrl(payload.merge_request_path);
}, },
[types.RECEIVE_CREATE_MERGE_REQUEST_ERROR](state) { [types.RECEIVE_CREATE_MERGE_REQUEST_ERROR](state) {
state.isCreatingIssue = false; state.isCreatingIssue = false;
......
...@@ -242,6 +242,7 @@ export default { ...@@ -242,6 +242,7 @@ export default {
<grouped-security-reports-app <grouped-security-reports-app
v-if="shouldRenderSecurityReport" v-if="shouldRenderSecurityReport"
:head-blob-path="mr.headBlobPath" :head-blob-path="mr.headBlobPath"
:source-branch="mr.sourceBranch"
:base-blob-path="mr.baseBlobPath" :base-blob-path="mr.baseBlobPath"
:sast-head-path="mr.sast.head_path" :sast-head-path="mr.sast.head_path"
:sast-base-path="mr.sast.base_path" :sast-base-path="mr.sast.base_path"
......
...@@ -64,7 +64,7 @@ export default { ...@@ -64,7 +64,7 @@ export default {
buttons.push(issueButton); buttons.push(issueButton);
} }
if (!this.vulnerability.hasMergeRequest) { if (!this.vulnerability.hasMergeRequest && this.remediation) {
buttons.push(MRButton); buttons.push(MRButton);
} }
...@@ -119,12 +119,11 @@ export default { ...@@ -119,12 +119,11 @@ export default {
const { data } = this.modal; const { data } = this.modal;
const result = {}; const result = {};
for (let key in data) { Object.keys(data).forEach(key => {
// debugger;
if (data[key].value && data[key].value.length) { if (data[key].value && data[key].value.length) {
result[key] = data[key]; result[key] = data[key];
} }
} });
return result; return result;
}, },
...@@ -273,7 +272,7 @@ export default { ...@@ -273,7 +272,7 @@ export default {
:author-name="mergeRequestFeedback.author.name" :author-name="mergeRequestFeedback.author.name"
:author-username="mergeRequestFeedback.author.username" :author-username="mergeRequestFeedback.author.username"
:action-link-text="`!${mergeRequestFeedback.merge_request_iid}`" :action-link-text="`!${mergeRequestFeedback.merge_request_iid}`"
:action-link-url="mergeRequestFeedback.merge_request_url" :action-link-url="mergeRequestFeedback.merge_request_path"
/> />
</li> </li>
</ul> </ul>
...@@ -331,6 +330,7 @@ export default { ...@@ -331,6 +330,7 @@ export default {
:disabled="actionButtons[0].isLoading" :disabled="actionButtons[0].isLoading"
:label="actionButtons[0].name" :label="actionButtons[0].name"
container-class="btn btn-success btn-inverted" container-class="btn btn-success btn-inverted"
class="js-action-button"
@click="$emit(actionButtons[0].action)" @click="$emit(actionButtons[0].action)"
/> />
</template> </template>
......
<script> <script>
import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { s__ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue';
export default { export default {
components: { components: {
GlDropdown, GlDropdown,
GlDropdownItem, GlDropdownItem,
Icon,
}, },
props: { props: {
buttons: { buttons: {
...@@ -33,16 +34,24 @@ export default { ...@@ -33,16 +34,24 @@ export default {
<template> <template>
<gl-dropdown <gl-dropdown
v-if="selectedButton" v-if="selectedButton"
split
no-caret no-caret
right
split
variant="success" variant="success"
:text="selectedButton.name" :text="selectedButton.name"
@click="handleClick" @click="handleClick"
> >
<gl-dropdown-item v-for="button in buttons" :key="button.action" @click="setButton(button)"> <gl-dropdown-item v-for="button in buttons" :key="button.action" @click="setButton(button)">
<div class="media">
<div>
<icon v-if="selectedButton === button" class="append-right-5" name="mobile-issue-close" />
</div>
<div class="media-body" :class="{ 'prepend-left-20': selectedButton !== button }">
<strong>{{ button.name }}</strong> <strong>{{ button.name }}</strong>
<br /> <br />
<span>{{ button.tagline }}</span> <span>{{ button.tagline }}</span>
</div>
</div>
</gl-dropdown-item> </gl-dropdown-item>
</gl-dropdown> </gl-dropdown>
</template> </template>
...@@ -29,6 +29,11 @@ export default { ...@@ -29,6 +29,11 @@ export default {
required: false, required: false,
default: null, default: null,
}, },
sourceBranch: {
type: String,
required: false,
default: null,
},
sastHeadPath: { sastHeadPath: {
type: String, type: String,
required: false, required: false,
...@@ -150,6 +155,7 @@ export default { ...@@ -150,6 +155,7 @@ export default {
created() { created() {
this.setHeadBlobPath(this.headBlobPath); this.setHeadBlobPath(this.headBlobPath);
this.setBaseBlobPath(this.baseBlobPath); this.setBaseBlobPath(this.baseBlobPath);
this.setSourceBranch(this.sourceBranch);
this.setVulnerabilityFeedbackPath(this.vulnerabilityFeedbackPath); this.setVulnerabilityFeedbackPath(this.vulnerabilityFeedbackPath);
this.setVulnerabilityFeedbackHelpPath(this.vulnerabilityFeedbackHelpPath); this.setVulnerabilityFeedbackHelpPath(this.vulnerabilityFeedbackHelpPath);
...@@ -199,6 +205,7 @@ export default { ...@@ -199,6 +205,7 @@ export default {
'setAppType', 'setAppType',
'setHeadBlobPath', 'setHeadBlobPath',
'setBaseBlobPath', 'setBaseBlobPath',
'setSourceBranch',
'setSastHeadPath', 'setSastHeadPath',
'setSastBasePath', 'setSastBasePath',
'setSastContainerHeadPath', 'setSastContainerHeadPath',
......
...@@ -26,6 +26,11 @@ export default { ...@@ -26,6 +26,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
sourceBranch: {
type: String,
required: false,
default: null,
},
sastHeadPath: { sastHeadPath: {
type: String, type: String,
required: false, required: false,
...@@ -141,6 +146,7 @@ export default { ...@@ -141,6 +146,7 @@ export default {
created() { created() {
// update the store with the received props // update the store with the received props
this.setHeadBlobPath(this.headBlobPath); this.setHeadBlobPath(this.headBlobPath);
this.setSourceBranch(this.sourceBranch);
this.setVulnerabilityFeedbackPath(this.vulnerabilityFeedbackPath); this.setVulnerabilityFeedbackPath(this.vulnerabilityFeedbackPath);
this.setVulnerabilityFeedbackHelpPath(this.vulnerabilityFeedbackHelpPath); this.setVulnerabilityFeedbackHelpPath(this.vulnerabilityFeedbackHelpPath);
this.setPipelineId(this.pipelineId); this.setPipelineId(this.pipelineId);
...@@ -183,6 +189,7 @@ export default { ...@@ -183,6 +189,7 @@ export default {
methods: { methods: {
...mapActions([ ...mapActions([
'setHeadBlobPath', 'setHeadBlobPath',
'setSourceBranch',
'setSastHeadPath', 'setSastHeadPath',
'setDependencyScanningHeadPath', 'setDependencyScanningHeadPath',
'setSastContainerHeadPath', 'setSastContainerHeadPath',
...@@ -199,6 +206,7 @@ export default { ...@@ -199,6 +206,7 @@ export default {
'dismissIssue', 'dismissIssue',
'revertDismissIssue', 'revertDismissIssue',
'createNewIssue', 'createNewIssue',
'createMergeRequest',
]), ]),
summaryTextBuilder(reportType, issuesCount = 0) { summaryTextBuilder(reportType, issuesCount = 0) {
if (issuesCount === 0) { if (issuesCount === 0) {
...@@ -282,6 +290,7 @@ export default { ...@@ -282,6 +290,7 @@ export default {
:can-create-issue-permission="canCreateIssuePermission" :can-create-issue-permission="canCreateIssuePermission"
:can-create-feedback-permission="canCreateFeedbackPermission" :can-create-feedback-permission="canCreateFeedbackPermission"
@createNewIssue="createNewIssue" @createNewIssue="createNewIssue"
@createMergeRequest="createMergeRequest"
@dismissIssue="dismissIssue" @dismissIssue="dismissIssue"
@revertDismissIssue="revertDismissIssue" @revertDismissIssue="revertDismissIssue"
/> />
......
...@@ -8,6 +8,8 @@ export const setHeadBlobPath = ({ commit }, blobPath) => commit(types.SET_HEAD_B ...@@ -8,6 +8,8 @@ export const setHeadBlobPath = ({ commit }, blobPath) => commit(types.SET_HEAD_B
export const setBaseBlobPath = ({ commit }, blobPath) => commit(types.SET_BASE_BLOB_PATH, blobPath); export const setBaseBlobPath = ({ commit }, blobPath) => commit(types.SET_BASE_BLOB_PATH, blobPath);
export const setSourceBranch = ({ commit }, branch) => commit(types.SET_SOURCE_BRANCH, branch);
export const setVulnerabilityFeedbackPath = ({ commit }, path) => export const setVulnerabilityFeedbackPath = ({ commit }, path) =>
commit(types.SET_VULNERABILITY_FEEDBACK_PATH, path); commit(types.SET_VULNERABILITY_FEEDBACK_PATH, path);
...@@ -335,6 +337,8 @@ export const createMergeRequest = ({ state, dispatch }) => { ...@@ -335,6 +337,8 @@ export const createMergeRequest = ({ state, dispatch }) => {
const { vulnerability } = state.modal; const { vulnerability } = state.modal;
const { category, project_fingerprint } = vulnerability; const { category, project_fingerprint } = vulnerability;
vulnerability.target_branch = state.sourceBranch;
dispatch('requestCreateMergeRequest'); dispatch('requestCreateMergeRequest');
axios axios
......
export const SET_HEAD_BLOB_PATH = 'SET_HEAD_BLOB_PATH'; export const SET_HEAD_BLOB_PATH = 'SET_HEAD_BLOB_PATH';
export const SET_BASE_BLOB_PATH = 'SET_BASE_BLOB_PATH'; export const SET_BASE_BLOB_PATH = 'SET_BASE_BLOB_PATH';
export const SET_SOURCE_BRANCH = 'SET_SOURCE_BRANCH';
export const SET_VULNERABILITY_FEEDBACK_PATH = 'SET_VULNERABILITY_FEEDBACK_PATH'; export const SET_VULNERABILITY_FEEDBACK_PATH = 'SET_VULNERABILITY_FEEDBACK_PATH';
export const SET_VULNERABILITY_FEEDBACK_HELP_PATH = 'SET_VULNERABILITY_FEEDBACK_HELP_PATH'; export const SET_VULNERABILITY_FEEDBACK_HELP_PATH = 'SET_VULNERABILITY_FEEDBACK_HELP_PATH';
export const SET_PIPELINE_ID = 'SET_PIPELINE_ID'; export const SET_PIPELINE_ID = 'SET_PIPELINE_ID';
......
...@@ -20,6 +20,10 @@ export default { ...@@ -20,6 +20,10 @@ export default {
Vue.set(state.blobPath, 'base', path); Vue.set(state.blobPath, 'base', path);
}, },
[types.SET_SOURCE_BRANCH](state, branch) {
state.sourceBranch = branch;
},
[types.SET_VULNERABILITY_FEEDBACK_PATH](state, path) { [types.SET_VULNERABILITY_FEEDBACK_PATH](state, path) {
state.vulnerabilityFeedbackPath = path; state.vulnerabilityFeedbackPath = path;
}, },
...@@ -419,7 +423,7 @@ export default { ...@@ -419,7 +423,7 @@ export default {
}, },
[types.RECEIVE_CREATE_MERGE_REQUEST_SUCCESS](state, payload) { [types.RECEIVE_CREATE_MERGE_REQUEST_SUCCESS](state, payload) {
// We don't cancel the loading state here because we're navigating away from the page // We don't cancel the loading state here because we're navigating away from the page
visitUrl(payload.merge_request_url); visitUrl(payload.merge_request_path);
}, },
[types.RECEIVE_CREATE_MERGE_REQUEST_ERROR](state, error) { [types.RECEIVE_CREATE_MERGE_REQUEST_ERROR](state, error) {
state.isCreatingMergeRequest = false; state.isCreatingMergeRequest = false;
......
...@@ -12,6 +12,7 @@ export default () => ({ ...@@ -12,6 +12,7 @@ export default () => ({
base: null, base: null,
}, },
sourceBranch: null,
vulnerabilityFeedbackPath: null, vulnerabilityFeedbackPath: null,
vulnerabilityFeedbackHelpPath: null, vulnerabilityFeedbackHelpPath: null,
pipelineId: null, pipelineId: null,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
dast_head_path: dast_endpoint, dast_head_path: dast_endpoint,
sast_container_head_path: sast_container_endpoint, sast_container_head_path: sast_container_endpoint,
pipeline_id: pipeline.id, pipeline_id: pipeline.id,
source_branch: pipeline.ref,
vulnerability_feedback_path: project_vulnerability_feedback_index_path(project), vulnerability_feedback_path: project_vulnerability_feedback_index_path(project),
vulnerability_feedback_help_path: help_page_path("user/project/merge_requests/index", anchor: "interacting-with-security-reports-ultimate"), vulnerability_feedback_help_path: help_page_path("user/project/merge_requests/index", anchor: "interacting-with-security-reports-ultimate"),
sast_help_path: help_page_path('user/project/merge_requests/sast'), sast_help_path: help_page_path('user/project/merge_requests/sast'),
......
...@@ -463,7 +463,7 @@ describe('issue creation', () => { ...@@ -463,7 +463,7 @@ describe('issue creation', () => {
describe('merge request creation', () => { describe('merge request creation', () => {
describe('createMergeRequest', () => { describe('createMergeRequest', () => {
const vulnerability = mockDataVulnerabilities[0]; const vulnerability = mockDataVulnerabilities[0];
const data = { merge_request_url: 'fakepath.html' }; const data = { merge_request_path: 'fakepath.html' };
let mock; let mock;
beforeEach(() => { beforeEach(() => {
......
...@@ -413,11 +413,11 @@ describe('vulnerabilities module mutations', () => { ...@@ -413,11 +413,11 @@ describe('vulnerabilities module mutations', () => {
describe('RECEIVE_CREATE_MERGE_REQUEST_SUCCESS', () => { describe('RECEIVE_CREATE_MERGE_REQUEST_SUCCESS', () => {
it('should fire the visitUrl function on the merge request URL', () => { it('should fire the visitUrl function on the merge request URL', () => {
const state = createState(); const state = createState();
const payload = { merge_request_url: 'fakepath.html' }; const payload = { merge_request_path: 'fakepath.html' };
const visitUrl = spyOnDependency(mutations, 'visitUrl'); const visitUrl = spyOnDependency(mutations, 'visitUrl');
mutations[types.RECEIVE_CREATE_MERGE_REQUEST_SUCCESS](state, payload); mutations[types.RECEIVE_CREATE_MERGE_REQUEST_SUCCESS](state, payload);
expect(visitUrl).toHaveBeenCalledWith(payload.merge_request_url); expect(visitUrl).toHaveBeenCalledWith(payload.merge_request_path);
}); });
}); });
......
...@@ -97,6 +97,10 @@ describe('Security Reports modal', () => { ...@@ -97,6 +97,10 @@ describe('Security Reports modal', () => {
expect(vm.$el.querySelector('.js-dismiss-btn')).toBe(null); expect(vm.$el.querySelector('.js-dismiss-btn')).toBe(null);
}); });
it('renders create issue button', () => {
expect(vm.$el.querySelector('.js-action-button')).not.toBe(null);
});
it('renders the footer', () => { it('renders the footer', () => {
expect(vm.$el.classList.contains('modal-hide-footer')).toEqual(false); expect(vm.$el.classList.contains('modal-hide-footer')).toEqual(false);
}); });
...@@ -104,7 +108,7 @@ describe('Security Reports modal', () => { ...@@ -104,7 +108,7 @@ describe('Security Reports modal', () => {
it('emits createIssue when create issue button is clicked', () => { it('emits createIssue when create issue button is clicked', () => {
spyOn(vm, '$emit'); spyOn(vm, '$emit');
const button = vm.$el.querySelector('.js-split-button').querySelector('.btn-success'); const button = vm.$el.querySelector('.js-action-button');
button.click(); button.click();
expect(vm.$emit).toHaveBeenCalledWith('createNewIssue'); expect(vm.$emit).toHaveBeenCalledWith('createNewIssue');
......
...@@ -517,11 +517,11 @@ describe('security reports mutations', () => { ...@@ -517,11 +517,11 @@ describe('security reports mutations', () => {
describe('RECEIVE_CREATE_MERGE_REQUEST_SUCCESS', () => { describe('RECEIVE_CREATE_MERGE_REQUEST_SUCCESS', () => {
it('should fire the visitUrl function on the merge request URL', () => { it('should fire the visitUrl function on the merge request URL', () => {
const payload = { merge_request_url: 'fakepath.html' }; const payload = { merge_request_path: 'fakepath.html' };
const visitUrl = spyOnDependency(mutations, 'visitUrl'); const visitUrl = spyOnDependency(mutations, 'visitUrl');
mutations[types.RECEIVE_CREATE_MERGE_REQUEST_SUCCESS](stateCopy, payload); mutations[types.RECEIVE_CREATE_MERGE_REQUEST_SUCCESS](stateCopy, payload);
expect(visitUrl).toHaveBeenCalledWith(payload.merge_request_url); expect(visitUrl).toHaveBeenCalledWith(payload.merge_request_path);
}); });
}); });
......
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