From 6d84de42e092f96ee8977ca9b509bd0e98af05c3 Mon Sep 17 00:00:00 2001 From: Anton Smith Date: Fri, 3 Oct 2025 15:16:29 +1300 Subject: [PATCH 1/2] Frontend: reconcile created Jira issues Implements frontend support for the search-and-reconcile method to fetch newly created Jira issues from vulnerabilities Changelog: changed EE: true --- .../security_reports/components/create_jira_issue.vue | 4 ++-- ...ulnerability_external_issue_link_create.mutation.graphql | 1 + .../vulnerabilities/components/related_jira_issues.vue | 6 ++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ee/app/assets/javascripts/vue_shared/security_reports/components/create_jira_issue.vue b/ee/app/assets/javascripts/vue_shared/security_reports/components/create_jira_issue.vue index 125d039df81659..deb7d811862319 100644 --- a/ee/app/assets/javascripts/vue_shared/security_reports/components/create_jira_issue.vue +++ b/ee/app/assets/javascripts/vue_shared/security_reports/components/create_jira_issue.vue @@ -53,12 +53,12 @@ export default { }, }); - const { errors } = data.vulnerabilityExternalIssueLinkCreate; + const { errors, jiraIssueId } = data.vulnerabilityExternalIssueLinkCreate; if (errors.length > 0) { throw new Error(errors[0]); } - this.$emit('mutated'); + this.$emit('mutated', jiraIssueId); } catch (e) { this.$emit('create-jira-issue-error', e.message); } finally { diff --git a/ee/app/assets/javascripts/vue_shared/security_reports/graphql/vulnerability_external_issue_link_create.mutation.graphql b/ee/app/assets/javascripts/vue_shared/security_reports/graphql/vulnerability_external_issue_link_create.mutation.graphql index b3deb0748348b2..d77a357e8855af 100644 --- a/ee/app/assets/javascripts/vue_shared/security_reports/graphql/vulnerability_external_issue_link_create.mutation.graphql +++ b/ee/app/assets/javascripts/vue_shared/security_reports/graphql/vulnerability_external_issue_link_create.mutation.graphql @@ -1,6 +1,7 @@ mutation vulnerabilityExternalIssueLinkCreate($input: VulnerabilityExternalIssueLinkCreateInput!) { vulnerabilityExternalIssueLinkCreate(input: $input) { errors + jiraIssueId externalIssueLink { id externalIssue { diff --git a/ee/app/assets/javascripts/vulnerabilities/components/related_jira_issues.vue b/ee/app/assets/javascripts/vulnerabilities/components/related_jira_issues.vue index e5fad7b5d69e2c..d1f030e1f7054e 100644 --- a/ee/app/assets/javascripts/vulnerabilities/components/related_jira_issues.vue +++ b/ee/app/assets/javascripts/vulnerabilities/components/related_jira_issues.vue @@ -83,10 +83,11 @@ export default { }, // note: this direct API call will be replaced when migrating the vulnerability details page to GraphQL // related epic: https://gitlab.com/groups/gitlab-org/-/epics/3657 - async fetchRelatedIssues() { + async fetchRelatedIssues(jiraIssueId = null) { this.isFetchingRelatedIssues = true; try { - const { data } = await axios.get(this.relatedJiraIssuesPath); + const params = jiraIssueId ? { reconcileIssues: jiraIssueId } : {}; + const { data } = await axios.get(this.relatedJiraIssuesPath, { params }); if (Array.isArray(data)) { this.relatedIssues = data; } @@ -94,6 +95,7 @@ export default { this.hasFetchIssuesError = true; } finally { this.isFetchingRelatedIssues = false; + this.isFetchingRelatedIssues = false; } }, }, -- GitLab From 59d1f41eb9867aa783bef6b468f95fa9b5a26820 Mon Sep 17 00:00:00 2001 From: Anton Smith Date: Fri, 3 Oct 2025 15:18:17 +1300 Subject: [PATCH 2/2] Add tests for changes --- .../components/apollo_mocks.js | 6 ++- .../components/create_jira_issue_spec.js | 4 +- .../related_jira_issues_spec.js | 48 +++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/ee/spec/frontend/vue_shared/security_reports/components/apollo_mocks.js b/ee/spec/frontend/vue_shared/security_reports/components/apollo_mocks.js index 70b8aabd84ac15..ec6df90f2ae6d1 100644 --- a/ee/spec/frontend/vue_shared/security_reports/components/apollo_mocks.js +++ b/ee/spec/frontend/vue_shared/security_reports/components/apollo_mocks.js @@ -1,7 +1,11 @@ -export const vulnerabilityExternalIssueLinkCreateMockFactory = ({ errors = [] } = {}) => ({ +export const vulnerabilityExternalIssueLinkCreateMockFactory = ({ + errors = [], + jiraIssueId = '12345', +} = {}) => ({ data: { vulnerabilityExternalIssueLinkCreate: { errors, + jiraIssueId: errors.length > 0 ? null : jiraIssueId, externalIssueLink: { id: '1', externalIssue: { diff --git a/ee/spec/frontend/vue_shared/security_reports/components/create_jira_issue_spec.js b/ee/spec/frontend/vue_shared/security_reports/components/create_jira_issue_spec.js index 0bd5447cd47ac9..4ff8544607b4b2 100644 --- a/ee/spec/frontend/vue_shared/security_reports/components/create_jira_issue_spec.js +++ b/ee/spec/frontend/vue_shared/security_reports/components/create_jira_issue_spec.js @@ -110,8 +110,8 @@ describe('create_jira_issue', () => { await clickButton(); }); - it('should emit mutated event', () => { - expect(wrapper.emitted('mutated')).not.toBe(undefined); + it('should emit mutated event with jira issue id', () => { + expect(wrapper.emitted('mutated')).toEqual([['12345']]); }); }); }); diff --git a/ee/spec/frontend/vulnerabilities/related_jira_issues_spec.js b/ee/spec/frontend/vulnerabilities/related_jira_issues_spec.js index bc32153e668d67..dfa17ab5b621d8 100644 --- a/ee/spec/frontend/vulnerabilities/related_jira_issues_spec.js +++ b/ee/spec/frontend/vulnerabilities/related_jira_issues_spec.js @@ -198,4 +198,52 @@ describe('EE RelatedJiraIssues Component', () => { expect(findRelatedJiraIssuesSection().isVisible()).toBe(false); }); }); + + describe('fetchRelatedIssues method', () => { + beforeEach(() => { + wrapper = createShallowWrapper(); + jest.spyOn(axios, 'get').mockResolvedValue({ data: [] }); + }); + + it('calls axios.get with empty params when no jiraIssueId provided', async () => { + await wrapper.vm.fetchRelatedIssues(); + + expect(axios.get).toHaveBeenCalledWith(defaultProvide.relatedJiraIssuesPath, { params: {} }); + }); + + it('calls axios.get with reconcileIssues param when jiraIssueId provided', async () => { + await wrapper.vm.fetchRelatedIssues('12345'); + + expect(axios.get).toHaveBeenCalledWith(defaultProvide.relatedJiraIssuesPath, { + params: { reconcileIssues: '12345' }, + }); + }); + }); + + describe('onJiraIssueCreated method', () => { + beforeEach(() => { + wrapper = createShallowWrapper(); + jest.spyOn(wrapper.vm, 'fetchRelatedIssues'); + }); + + it('calls fetchRelatedIssues with the provided jiraIssueId', () => { + wrapper.vm.onJiraIssueCreated('12345'); + + expect(wrapper.vm.fetchRelatedIssues).toHaveBeenCalledWith('12345'); + }); + }); + + describe('createJiraIssue component integration', () => { + beforeEach(() => { + wrapper = createShallowWrapper(); + jest.spyOn(wrapper.vm, 'onJiraIssueCreated'); + }); + + it('calls onJiraIssueCreated when createJiraIssue emits mutated event with jiraIssueId', () => { + const jiraIssueId = '12345'; + findCreateJiraIssueComponent().vm.$emit('mutated', jiraIssueId); + + expect(wrapper.vm.onJiraIssueCreated).toHaveBeenCalledWith(jiraIssueId); + }); + }); }); -- GitLab