From 8dbb494437d9c5779b59bd93cc0637feb1ff6d3e Mon Sep 17 00:00:00 2001 From: Jiaan Louw Date: Tue, 6 Apr 2021 15:16:43 +0200 Subject: [PATCH 1/2] Add jira association missing state to MR widget - Adds a new MR state jiraAssociationMissing - Adds a MrWidgetJiraAssociationMissing component --- .../mr_widget_jira_association_missing.vue | 22 +++++++++++++ .../mr_widget_options.vue | 2 ++ .../stores/get_state_key.js | 4 +++ .../stores/mr_widget_store.js | 1 + .../stores/state_maps.js | 2 ++ .../store/get_state_key_spec.js | 30 +++++++++++++++++ ...mr_widget_jira_association_missing_spec.js | 32 +++++++++++++++++++ locale/gitlab.pot | 3 ++ 8 files changed, 96 insertions(+) create mode 100644 ee/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_jira_association_missing.vue create mode 100644 ee/spec/frontend/license_compliance/store/get_state_key_spec.js create mode 100644 ee/spec/frontend/vue_mr_widget/components/states/mr_widget_jira_association_missing_spec.js diff --git a/ee/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_jira_association_missing.vue b/ee/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_jira_association_missing.vue new file mode 100644 index 00000000000000..527f9466a676a0 --- /dev/null +++ b/ee/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_jira_association_missing.vue @@ -0,0 +1,22 @@ + + diff --git a/ee/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/ee/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index e08c1cf5c1102e..c7103a4c0eb99b 100644 --- a/ee/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/ee/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -10,6 +10,7 @@ import { s__, __, sprintf } from '~/locale'; import ReportSection from '~/reports/components/report_section.vue'; import CEWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue'; import BlockingMergeRequestsReport from './components/blocking_merge_requests/blocking_merge_requests_report.vue'; +import MrWidgetJiraAssociationMissing from './components/states/mr_widget_jira_association_missing.vue'; import MrWidgetPolicyViolation from './components/states/mr_widget_policy_violation.vue'; import MrWidgetGeoSecondaryNode from './components/states/mr_widget_secondary_geo_node.vue'; @@ -18,6 +19,7 @@ export default { MrWidgetLicenses, MrWidgetGeoSecondaryNode, MrWidgetPolicyViolation, + MrWidgetJiraAssociationMissing, BlockingMergeRequestsReport, GroupedSecurityReportsApp: () => import('ee/vue_shared/security_reports/grouped_security_reports_app.vue'), diff --git a/ee/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js b/ee/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js index edffbeacb2463a..3cf76cd66e5170 100644 --- a/ee/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js +++ b/ee/app/assets/javascripts/vue_merge_request_widget/stores/get_state_key.js @@ -10,5 +10,9 @@ export default function getStateKey() { return stateKey.policyViolation; } + if (this.jiraAssociation.enforced && this.jiraAssociation.issue_keys.length === 0) { + return stateKey.jiraAssociationMissing; + } + return CEGetStateKey.call(this); } diff --git a/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js b/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js index d3cc1f6761e356..af5e01eb161a9a 100644 --- a/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js +++ b/ee/app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js @@ -46,6 +46,7 @@ export default class MergeRequestStore extends CEMergeRequestStore { this.mergeTrainsCount = data.merge_trains_count || 0; this.mergeTrainIndex = data.merge_train_index; this.policyViolation = data.policy_violation; + this.jiraAssociation = data.jira_associations || {}; super.setData(data, isRebased); } diff --git a/ee/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js b/ee/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js index 5b115744719812..57c7f33f4aa538 100644 --- a/ee/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js +++ b/ee/app/assets/javascripts/vue_merge_request_widget/stores/state_maps.js @@ -2,9 +2,11 @@ import stateMaps from '~/vue_merge_request_widget/stores/state_maps'; stateMaps.stateToComponentMap.geoSecondaryNode = 'mr-widget-geo-secondary-node'; stateMaps.stateToComponentMap.policyViolation = 'mr-widget-policy-violation'; +stateMaps.stateToComponentMap.jiraAssociationMissing = 'mr-widget-jira-association-missing'; export const stateKey = { policyViolation: 'policyViolation', + jiraAssociationMissing: 'jiraAssociationMissing', }; export default { diff --git a/ee/spec/frontend/license_compliance/store/get_state_key_spec.js b/ee/spec/frontend/license_compliance/store/get_state_key_spec.js new file mode 100644 index 00000000000000..aadabd26d68e24 --- /dev/null +++ b/ee/spec/frontend/license_compliance/store/get_state_key_spec.js @@ -0,0 +1,30 @@ +import getStateKey from 'ee/vue_merge_request_widget/stores/get_state_key'; + +describe('getStateKey', () => { + const canMergeContext = { + canMerge: true, + commitsCount: 2, + }; + + describe('jiraAssociationMissing', () => { + const createContext = (enforced, issueCount) => ({ + ...canMergeContext, + jiraAssociation: { + enforced, + issue_keys: new Array(issueCount), + }, + }); + + it.each` + scenario | context | state + ${'enforced with issues'} | ${createContext(true, 1)} | ${null} + ${'enforced without issues'} | ${createContext(true, 0)} | ${'jiraAssociationMissing'} + ${'not enforced with issues'} | ${createContext(false, 1)} | ${null} + ${'not enforced without issues'} | ${createContext(false, 0)} | ${null} + `('when $scenario, state should equal $state', ({ context, state }) => { + const bound = getStateKey.bind(context); + + expect(bound()).toEqual(state); + }); + }); +}); diff --git a/ee/spec/frontend/vue_mr_widget/components/states/mr_widget_jira_association_missing_spec.js b/ee/spec/frontend/vue_mr_widget/components/states/mr_widget_jira_association_missing_spec.js new file mode 100644 index 00000000000000..744e4c7109ca3f --- /dev/null +++ b/ee/spec/frontend/vue_mr_widget/components/states/mr_widget_jira_association_missing_spec.js @@ -0,0 +1,32 @@ +import { shallowMount } from '@vue/test-utils'; +import MrWidgetJiraAssociationMissing from 'ee/vue_merge_request_widget/components/states/mr_widget_jira_association_missing.vue'; +import StatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue'; + +describe('MrWidgetJiraAssociationMissing', () => { + let wrapper; + + const findStatusIcon = () => wrapper.find(StatusIcon); + + const createComponent = () => { + wrapper = shallowMount(MrWidgetJiraAssociationMissing); + }; + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + beforeEach(() => { + createComponent(); + }); + + it('shows the disabled merge button', () => { + expect(findStatusIcon().props('showDisabledButton')).toBe(true); + }); + + it('shows the disabled reason', () => { + expect(wrapper.text()).toContain( + 'To merge, a Jira issue key must be mentioned in the title or description.', + ); + }); +}); diff --git a/locale/gitlab.pot b/locale/gitlab.pot index e4e877f5f43e25..3d7223805a078d 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -36888,6 +36888,9 @@ msgstr "" msgid "mrWidget|To approve this merge request, please enter your password. This project requires all approvals to be authenticated." msgstr "" +msgid "mrWidget|To merge, a Jira issue key must be mentioned in the title or description." +msgstr "" + msgid "mrWidget|Use %{linkStart}CI pipelines to test your code%{linkEnd} by simply adding a GitLab CI configuration file to your project. It only takes a minute to make your code more secure and robust." msgstr "" -- GitLab From e26b9124bf0dd57d0bc5a38eedafaca2914c58f3 Mon Sep 17 00:00:00 2001 From: Jiaan Louw Date: Wed, 7 Apr 2021 16:54:04 +0200 Subject: [PATCH 2/2] Apply reviewer feedback to get_state_key spec --- .../store/get_state_key_spec.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ee/spec/frontend/license_compliance/store/get_state_key_spec.js b/ee/spec/frontend/license_compliance/store/get_state_key_spec.js index aadabd26d68e24..bb168a242fd8c1 100644 --- a/ee/spec/frontend/license_compliance/store/get_state_key_spec.js +++ b/ee/spec/frontend/license_compliance/store/get_state_key_spec.js @@ -7,24 +7,24 @@ describe('getStateKey', () => { }; describe('jiraAssociationMissing', () => { - const createContext = (enforced, issueCount) => ({ + const createContext = (enforced, hasIssues) => ({ ...canMergeContext, jiraAssociation: { enforced, - issue_keys: new Array(issueCount), + issue_keys: hasIssues ? [1] : [], }, }); it.each` - scenario | context | state - ${'enforced with issues'} | ${createContext(true, 1)} | ${null} - ${'enforced without issues'} | ${createContext(true, 0)} | ${'jiraAssociationMissing'} - ${'not enforced with issues'} | ${createContext(false, 1)} | ${null} - ${'not enforced without issues'} | ${createContext(false, 0)} | ${null} - `('when $scenario, state should equal $state', ({ context, state }) => { - const bound = getStateKey.bind(context); + scenario | enforced | hasIssues | state + ${'enforced with issues'} | ${true} | ${true} | ${null} + ${'enforced without issues'} | ${true} | ${false} | ${'jiraAssociationMissing'} + ${'not enforced with issues'} | ${false} | ${true} | ${null} + ${'not enforced without issues'} | ${false} | ${false} | ${null} + `('when $scenario, state should equal $state', ({ enforced, hasIssues, state }) => { + const bound = getStateKey.bind(createContext(enforced, hasIssues)); - expect(bound()).toEqual(state); + expect(bound()).toBe(state); }); }); }); -- GitLab