Commit 646522cc authored by Fernando's avatar Fernando

Add MR widget support for license check

* Add vue component
* Add mapping and keys

Add missing stateKey

Add support for license check approval group

* Account for license check approval rule being enabled
* Show corrext messaging in the UI if the rule is enabled

Update POT files and translations

* Regenerate POT files

Add getters unit tests

* Refactor unit tests and add new ones

Run prettier and linter

* Fix pipeline errors

Add mr widget license compliance approval group action tests

* Add unit tests

Add mutation specs for approvals

* Add unit tests

Add specs for mr widget approval vue

* Add unit tests
parent d6f7cbd1
...@@ -15,6 +15,7 @@ export default () => { ...@@ -15,6 +15,7 @@ export default () => {
apiUrl, apiUrl,
licenseManagementSettingsPath, licenseManagementSettingsPath,
licensesApiPath, licensesApiPath,
approvalsApiPath,
} = licensesTab.dataset; } = licensesTab.dataset;
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
...@@ -29,6 +30,7 @@ export default () => { ...@@ -29,6 +30,7 @@ export default () => {
apiUrl, apiUrl,
licensesApiPath, licensesApiPath,
licenseManagementSettingsPath, licenseManagementSettingsPath,
approvalsApiPath,
canManageLicenses: parseBoolean(canManageLicenses), canManageLicenses: parseBoolean(canManageLicenses),
alwaysOpen: true, alwaysOpen: true,
reportSectionClass: 'split-report-section', reportSectionClass: 'split-report-section',
......
<script>
import statusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
export default {
name: 'MRWidgetPolicyViolation',
components: {
statusIcon,
},
};
</script>
<template>
<div class="mr-widget-body media">
<div class="space-children">
<status-icon status="warning" />
<button type="button" class="btn btn-success btn-sm" disabled="true">
{{ s__('mrWidget|Merge') }}
</button>
</div>
<div class="media-body">
<span class="bold">
{{ s__('mrWidget|You can only merge once the denied license is removed') }}
</span>
</div>
</div>
</template>
...@@ -12,6 +12,7 @@ import { n__, s__, __, sprintf } from '~/locale'; ...@@ -12,6 +12,7 @@ import { n__, s__, __, sprintf } from '~/locale';
import CEWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue'; import CEWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue';
import MrWidgetApprovals from './components/approvals/approvals.vue'; import MrWidgetApprovals from './components/approvals/approvals.vue';
import MrWidgetGeoSecondaryNode from './components/states/mr_widget_secondary_geo_node.vue'; import MrWidgetGeoSecondaryNode from './components/states/mr_widget_secondary_geo_node.vue';
import MrWidgetPolicyViolation from './components/states/mr_widget_policy_violation.vue';
import MergeTrainHelperText from './components/merge_train_helper_text.vue'; import MergeTrainHelperText from './components/merge_train_helper_text.vue';
import { MTWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants'; import { MTWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants';
...@@ -21,6 +22,7 @@ export default { ...@@ -21,6 +22,7 @@ export default {
MrWidgetLicenses, MrWidgetLicenses,
MrWidgetApprovals, MrWidgetApprovals,
MrWidgetGeoSecondaryNode, MrWidgetGeoSecondaryNode,
MrWidgetPolicyViolation,
BlockingMergeRequestsReport, BlockingMergeRequestsReport,
GroupedSecurityReportsApp, GroupedSecurityReportsApp,
GroupedMetricsReportsApp, GroupedMetricsReportsApp,
...@@ -358,6 +360,7 @@ export default { ...@@ -358,6 +360,7 @@ export default {
<mr-widget-licenses <mr-widget-licenses
v-if="shouldRenderLicenseReport" v-if="shouldRenderLicenseReport"
:api-url="mr.licenseScanning.managed_licenses_path" :api-url="mr.licenseScanning.managed_licenses_path"
:approvals-api-path="mr.apiApprovalsPath"
:licenses-api-path="licensesApiPath" :licenses-api-path="licensesApiPath"
:pipeline-path="mr.pipeline.path" :pipeline-path="mr.pipeline.path"
:can-manage-licenses="mr.licenseScanning.can_manage_licenses" :can-manage-licenses="mr.licenseScanning.can_manage_licenses"
......
import CEGetStateKey from '~/vue_merge_request_widget/stores/get_state_key'; import CEGetStateKey from '~/vue_merge_request_widget/stores/get_state_key';
import { stateKey } from './state_maps';
export default function(data) { export default function(data) {
if (this.isGeoSecondaryNode) { if (this.isGeoSecondaryNode) {
return 'geoSecondaryNode'; return 'geoSecondaryNode';
} }
if (data.policy_violation) {
return stateKey.policyViolation;
}
return CEGetStateKey.call(this, data); return CEGetStateKey.call(this, data);
} }
import stateMaps from '~/vue_merge_request_widget/stores/state_maps'; import stateMaps from '~/vue_merge_request_widget/stores/state_maps';
stateMaps.stateToComponentMap.geoSecondaryNode = 'mr-widget-geo-secondary-node'; stateMaps.stateToComponentMap.geoSecondaryNode = 'mr-widget-geo-secondary-node';
stateMaps.stateToComponentMap.policyViolation = 'mr-widget-policy-violation';
export const stateKey = {
policyViolation: 'policyViolation',
};
export default { export default {
stateToComponentMap: stateMaps.stateToComponentMap, stateToComponentMap: stateMaps.stateToComponentMap,
......
...@@ -46,6 +46,11 @@ export default { ...@@ -46,6 +46,11 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
approvalsApiPath: {
type: String,
required: false,
default: '',
},
canManageLicenses: { canManageLicenses: {
type: Boolean, type: Boolean,
required: true, required: true,
...@@ -94,18 +99,31 @@ export default { ...@@ -94,18 +99,31 @@ export default {
}, },
}, },
mounted() { mounted() {
const { apiUrl, canManageLicenses, licensesApiPath } = this; const { apiUrl, canManageLicenses, licensesApiPath, approvalsApiPath } = this;
this.setAPISettings({ this.setAPISettings({
apiUrlManageLicenses: apiUrl, apiUrlManageLicenses: apiUrl,
canManageLicenses, canManageLicenses,
licensesApiPath, licensesApiPath,
approvalsApiPath,
}); });
this.fetchParsedLicenseReport(); this.fetchParsedLicenseReport();
/*
If we render this widget from the "License" tab in the pipeline view,
then we don't fetch the approvals since we aren't in the Merge request context.
*/
if (approvalsApiPath) {
this.fetchLicenseCheckApprovalRule();
}
}, },
methods: { methods: {
...mapActions(LICENSE_MANAGEMENT, ['setAPISettings', 'fetchParsedLicenseReport']), ...mapActions(LICENSE_MANAGEMENT, [
'setAPISettings',
'fetchParsedLicenseReport',
'fetchLicenseCheckApprovalRule',
]),
}, },
}; };
</script> </script>
......
...@@ -111,6 +111,37 @@ export const receiveSetLicenseApprovalError = ({ commit }, error) => { ...@@ -111,6 +111,37 @@ export const receiveSetLicenseApprovalError = ({ commit }, error) => {
commit(types.RECEIVE_SET_LICENSE_APPROVAL_ERROR, error); commit(types.RECEIVE_SET_LICENSE_APPROVAL_ERROR, error);
}; };
export const fetchLicenseCheckApprovalRule = ({ dispatch, state }) => {
dispatch('requestLicenseCheckApprovalRule');
axios
.get(state.approvalsApiPath)
.then(({ data }) => {
const hasLicenseCheckApprovalRule = Boolean(
data.approval_rules_left.find(rule => {
return rule.name === 'License-Check';
}),
);
dispatch('receiveLicenseCheckApprovalRuleSuccess', { hasLicenseCheckApprovalRule });
})
.catch(error => {
dispatch('receiveLicenseCheckApprovalRuleError', error);
});
};
export const requestLicenseCheckApprovalRule = ({ commit }) => {
commit(types.REQUEST_LICENSE_CHECK_APPROVAL_RULE);
};
export const receiveLicenseCheckApprovalRuleSuccess = ({ commit }, rule) => {
commit(types.RECEIVE_LICENSE_CHECK_APPROVAL_RULE_SUCCESS, rule);
};
export const receiveLicenseCheckApprovalRuleError = ({ commit }, error) => {
commit(types.RECEIVE_LICENSE_CHECK_APPROVAL_RULE_ERROR, error);
};
export const setIsAdmin = ({ commit }, payload) => { export const setIsAdmin = ({ commit }, payload) => {
commit(types.SET_IS_ADMIN, payload); commit(types.SET_IS_ADMIN, payload);
}; };
......
...@@ -2,7 +2,10 @@ import { n__, s__, sprintf } from '~/locale'; ...@@ -2,7 +2,10 @@ import { n__, s__, sprintf } from '~/locale';
import { addLicensesMatchingReportGroupStatus, reportGroupHasAtLeastOneLicense } from './utils'; import { addLicensesMatchingReportGroupStatus, reportGroupHasAtLeastOneLicense } from './utils';
import { LICENSE_APPROVAL_STATUS, REPORT_GROUPS } from '../constants'; import { LICENSE_APPROVAL_STATUS, REPORT_GROUPS } from '../constants';
export const isLoading = state => state.isLoadingManagedLicenses || state.isLoadingLicenseReport; export const isLoading = state =>
state.isLoadingManagedLicenses ||
state.isLoadingLicenseReport ||
state.isLoadingLicenseCheckApprovalRule;
export const isLicenseBeingUpdated = state => (id = null) => state.pendingLicenses.includes(id); export const isLicenseBeingUpdated = state => (id = null) => state.pendingLicenses.includes(id);
...@@ -17,10 +20,19 @@ export const licenseReportGroups = state => ...@@ -17,10 +20,19 @@ export const licenseReportGroups = state =>
reportGroupHasAtLeastOneLicense, reportGroupHasAtLeastOneLicense,
); );
export const licenseSummaryText = (state, getters) => { export const hasReportItems = (_, getters) => {
const hasReportItems = getters.licenseReport && getters.licenseReport.length; return getters.licenseReport && getters.licenseReport.length;
const baseReportHasLicenses = state.existingLicenses.length; };
export const baseReportHasLicenses = state => {
return state.existingLicenses.length;
};
export const licenseReportLength = (_, getters) => {
return getters.licenseReport.length;
};
export const licenseSummaryText = (state, getters) => {
if (getters.isLoading) { if (getters.isLoading) {
return sprintf(s__('ciReport|Loading %{reportName} report'), { return sprintf(s__('ciReport|Loading %{reportName} report'), {
reportName: s__('License Compliance'), reportName: s__('License Compliance'),
...@@ -33,43 +45,75 @@ export const licenseSummaryText = (state, getters) => { ...@@ -33,43 +45,75 @@ export const licenseSummaryText = (state, getters) => {
}); });
} }
if (hasReportItems) { if (getters.hasReportItems) {
const licenseReportLength = getters.licenseReport.length; return state.hasLicenseCheckApprovalRule
? getters.summaryTextWithLicenseCheck
if (!baseReportHasLicenses) { : getters.summaryTextWithoutLicenseCheck;
return getters.reportContainsBlacklistedLicense }
? n__(
'LicenseCompliance|License Compliance detected %d license and policy violation for the source branch only; approval required',
'LicenseCompliance|License Compliance detected %d licenses and policy violations for the source branch only; approval required',
licenseReportLength,
)
: n__(
'LicenseCompliance|License Compliance detected %d license for the source branch only',
'LicenseCompliance|License Compliance detected %d licenses for the source branch only',
licenseReportLength,
);
}
if (!getters.baseReportHasLicenses) {
return s__(
'LicenseCompliance|License Compliance detected no licenses for the source branch only',
);
}
return s__('LicenseCompliance|License Compliance detected no new licenses');
};
export const summaryTextWithLicenseCheck = (_, getters) => {
if (!getters.baseReportHasLicenses) {
return getters.reportContainsBlacklistedLicense return getters.reportContainsBlacklistedLicense
? n__( ? n__(
'LicenseCompliance|License Compliance detected %d new license and policy violation; approval required', 'LicenseCompliance|License Compliance detected %d license and policy violation for the source branch only; approval required',
'LicenseCompliance|License Compliance detected %d new licenses and policy violations; approval required', 'LicenseCompliance|License Compliance detected %d licenses and policy violations for the source branch only; approval required',
licenseReportLength, getters.licenseReportLength,
) )
: n__( : n__(
'LicenseCompliance|License Compliance detected %d new license', 'LicenseCompliance|License Compliance detected %d license for the source branch only',
'LicenseCompliance|License Compliance detected %d new licenses', 'LicenseCompliance|License Compliance detected %d licenses for the source branch only',
licenseReportLength, getters.licenseReportLength,
); );
} }
if (!baseReportHasLicenses) { return getters.reportContainsBlacklistedLicense
return s__( ? n__(
'LicenseCompliance|License Compliance detected no licenses for the source branch only', 'LicenseCompliance|License Compliance detected %d new license and policy violation; approval required',
); 'LicenseCompliance|License Compliance detected %d new licenses and policy violations; approval required',
getters.licenseReportLength,
)
: n__(
'LicenseCompliance|License Compliance detected %d new license',
'LicenseCompliance|License Compliance detected %d new licenses',
getters.licenseReportLength,
);
};
export const summaryTextWithoutLicenseCheck = (_, getters) => {
if (!getters.baseReportHasLicenses) {
return getters.reportContainsBlacklistedLicense
? n__(
'LicenseCompliance|License Compliance detected %d license and policy violation for the source branch only',
'LicenseCompliance|License Compliance detected %d licenses and policy violations for the source branch only',
getters.licenseReportLength,
)
: n__(
'LicenseCompliance|License Compliance detected %d license for the source branch only',
'LicenseCompliance|License Compliance detected %d licenses for the source branch only',
getters.licenseReportLength,
);
} }
return s__('LicenseCompliance|License Compliance detected no new licenses'); return getters.reportContainsBlacklistedLicense
? n__(
'LicenseCompliance|License Compliance detected %d new license and policy violation',
'LicenseCompliance|License Compliance detected %d new licenses and policy violations',
getters.licenseReportLength,
)
: n__(
'LicenseCompliance|License Compliance detected %d new license',
'LicenseCompliance|License Compliance detected %d new licenses',
getters.licenseReportLength,
);
}; };
export const reportContainsBlacklistedLicense = (_, getters) => export const reportContainsBlacklistedLicense = (_, getters) =>
......
...@@ -16,6 +16,11 @@ export const SET_LICENSE_IN_MODAL = 'SET_LICENSE_IN_MODAL'; ...@@ -16,6 +16,11 @@ export const SET_LICENSE_IN_MODAL = 'SET_LICENSE_IN_MODAL';
export const SET_IS_ADMIN = 'SET_IS_ADMIN'; export const SET_IS_ADMIN = 'SET_IS_ADMIN';
export const ADD_PENDING_LICENSE = 'ADD_PENDING_LICENSE'; export const ADD_PENDING_LICENSE = 'ADD_PENDING_LICENSE';
export const REMOVE_PENDING_LICENSE = 'REMOVE_PENDING_LICENSE'; export const REMOVE_PENDING_LICENSE = 'REMOVE_PENDING_LICENSE';
export const REQUEST_LICENSE_CHECK_APPROVAL_RULE = 'REQUEST_LICENSE_CHECK_APPROVAL_RULE';
export const RECEIVE_LICENSE_CHECK_APPROVAL_RULE_SUCCESS =
'RECEIVE_LICENSE_CHECK_APPROVAL_RULE_SUCCESS';
export const RECEIVE_LICENSE_CHECK_APPROVAL_RULE_ERROR =
'RECEIVE_LICENSE_CHECK_APPROVAL_RULE_ERROR';
// prevent babel-plugin-rewire from generating an invalid default during karma tests // prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {}; export default () => {};
...@@ -96,6 +96,22 @@ export default { ...@@ -96,6 +96,22 @@ export default {
currentLicenseInModal: null, currentLicenseInModal: null,
}); });
}, },
[types.REQUEST_LICENSE_CHECK_APPROVAL_RULE](state) {
Object.assign(state, {
isLoadingLicenseCheckApprovalRule: true,
});
},
[types.RECEIVE_LICENSE_CHECK_APPROVAL_RULE_SUCCESS](state, { hasLicenseCheckApprovalRule }) {
Object.assign(state, {
isLoadingLicenseCheckApprovalRule: false,
hasLicenseCheckApprovalRule,
});
},
[types.RECEIVE_LICENSE_CHECK_APPROVAL_RULE_ERROR](state) {
Object.assign(state, {
isLoadingLicenseCheckApprovalRule: false,
});
},
[types.ADD_PENDING_LICENSE](state, id) { [types.ADD_PENDING_LICENSE](state, id) {
state.pendingLicenses.push(id); state.pendingLicenses.push(id);
}, },
......
export default () => ({ export default () => ({
apiUrlManageLicenses: null, apiUrlManageLicenses: null,
approvalsApiPath: null,
licensesApiPath: null, licensesApiPath: null,
canManageLicenses: false, canManageLicenses: false,
currentLicenseInModal: null, currentLicenseInModal: null,
...@@ -14,4 +15,6 @@ export default () => ({ ...@@ -14,4 +15,6 @@ export default () => ({
managedLicenses: [], managedLicenses: [],
newLicenses: [], newLicenses: [],
existingLicenses: [], existingLicenses: [],
hasLicenseCheckApprovalRule: false,
isLoadingLicenseCheckApprovalRule: false,
}); });
import { shallowMount } from '@vue/test-utils';
import MrWidgetPolicyViolation from 'ee/vue_merge_request_widget/components/states/mr_widget_policy_violation.vue';
describe('EE MrWidgetPolicyViolation', () => {
let wrapper;
const findButton = () => wrapper.find('button');
const createComponent = () => {
wrapper = shallowMount(MrWidgetPolicyViolation, {});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('when shown', () => {
beforeEach(() => {
createComponent();
});
it('shows the disabled merge button', () => {
expect(wrapper.text()).toContain('Merge');
expect(findButton().attributes().disabled).toBe('disabled');
});
it('shows the disabled reason', () => {
expect(wrapper.text()).toContain('You can only merge once the denied license is removed');
});
});
});
...@@ -48,6 +48,7 @@ describe('License Report MR Widget', () => { ...@@ -48,6 +48,7 @@ describe('License Report MR Widget', () => {
loadingText: 'LOADING', loadingText: 'LOADING',
errorText: 'ERROR', errorText: 'ERROR',
licensesApiPath: `${TEST_HOST}/parsed_license_report.json`, licensesApiPath: `${TEST_HOST}/parsed_license_report.json`,
approvalsApiPath: `${TEST_HOST}/path/to/approvals`,
canManageLicenses: true, canManageLicenses: true,
licenseManagementSettingsPath: `${TEST_HOST}/lm_settings`, licenseManagementSettingsPath: `${TEST_HOST}/lm_settings`,
fullReportPath: `${TEST_HOST}/path/to/the/full/report`, fullReportPath: `${TEST_HOST}/path/to/the/full/report`,
...@@ -59,6 +60,7 @@ describe('License Report MR Widget', () => { ...@@ -59,6 +60,7 @@ describe('License Report MR Widget', () => {
setAPISettings: () => {}, setAPISettings: () => {},
fetchManagedLicenses: () => {}, fetchManagedLicenses: () => {},
fetchParsedLicenseReport: () => {}, fetchParsedLicenseReport: () => {},
fetchLicenseCheckApprovalRule: () => {},
}; };
const mountComponent = ({ const mountComponent = ({
...@@ -341,6 +343,7 @@ describe('License Report MR Widget', () => { ...@@ -341,6 +343,7 @@ describe('License Report MR Widget', () => {
const actions = { const actions = {
setAPISettings: jest.fn(() => {}), setAPISettings: jest.fn(() => {}),
fetchParsedLicenseReport: jest.fn(() => {}), fetchParsedLicenseReport: jest.fn(() => {}),
fetchLicenseCheckApprovalRule: jest.fn(() => {}),
}; };
mountComponent({ actions }); mountComponent({ actions });
...@@ -349,6 +352,7 @@ describe('License Report MR Widget', () => { ...@@ -349,6 +352,7 @@ describe('License Report MR Widget', () => {
{ {
apiUrlManageLicenses: apiUrl, apiUrlManageLicenses: apiUrl,
licensesApiPath: defaultProps.licensesApiPath, licensesApiPath: defaultProps.licensesApiPath,
approvalsApiPath: defaultProps.approvalsApiPath,
canManageLicenses: true, canManageLicenses: true,
}, },
undefined, undefined,
......
...@@ -10,6 +10,7 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -10,6 +10,7 @@ import axios from '~/lib/utils/axios_utils';
describe('License store actions', () => { describe('License store actions', () => {
const apiUrlManageLicenses = `${TEST_HOST}/licenses/management`; const apiUrlManageLicenses = `${TEST_HOST}/licenses/management`;
const approvalsApiPath = `${TEST_HOST}/approvalsApiPath`;
const licensesApiPath = `${TEST_HOST}/licensesApiPath`; const licensesApiPath = `${TEST_HOST}/licensesApiPath`;
let axiosMock; let axiosMock;
...@@ -26,6 +27,7 @@ describe('License store actions', () => { ...@@ -26,6 +27,7 @@ describe('License store actions', () => {
state = { state = {
...createState(), ...createState(),
apiUrlManageLicenses, apiUrlManageLicenses,
approvalsApiPath,
currentLicenseInModal: approvedLicense, currentLicenseInModal: approvedLicense,
}; };
licenseId = approvedLicense.id; licenseId = approvedLicense.id;
...@@ -480,6 +482,122 @@ describe('License store actions', () => { ...@@ -480,6 +482,122 @@ describe('License store actions', () => {
}); });
}); });
describe('fetchLicenseCheckApprovalRule ', () => {
it('dispatches request/receive with detected approval rule', done => {
const APPROVAL_RULE_RESPONSE = {
approval_rules_left: [{ name: 'License-Check' }],
};
axiosMock.onGet(approvalsApiPath).replyOnce(200, APPROVAL_RULE_RESPONSE);
testAction(
actions.fetchLicenseCheckApprovalRule,
null,
state,
[],
[
{ type: 'requestLicenseCheckApprovalRule' },
{
type: 'receiveLicenseCheckApprovalRuleSuccess',
payload: { hasLicenseCheckApprovalRule: true },
},
],
done,
);
});
it('dispatches request/receive without detected approval rule', done => {
const APPROVAL_RULE_RESPONSE = {
approval_rules_left: [{ name: 'Another Approval Rule' }],
};
axiosMock.onGet(approvalsApiPath).replyOnce(200, APPROVAL_RULE_RESPONSE);
testAction(
actions.fetchLicenseCheckApprovalRule,
null,
state,
[],
[
{ type: 'requestLicenseCheckApprovalRule' },
{
type: 'receiveLicenseCheckApprovalRuleSuccess',
payload: { hasLicenseCheckApprovalRule: false },
},
],
done,
);
});
it('dispatches request/receive on error', done => {
const error = new Error('Request failed with status code 500');
axiosMock.onGet(approvalsApiPath).replyOnce(500);
testAction(
actions.fetchLicenseCheckApprovalRule,
null,
state,
[],
[
{ type: 'requestLicenseCheckApprovalRule' },
{ type: 'receiveLicenseCheckApprovalRuleError', payload: error },
],
done,
);
});
});
describe('requestLicenseCheckApprovalRule', () => {
it('commits REQUEST_LICENSE_CHECK_APPROVAL_RULE', done => {
testAction(
actions.requestLicenseCheckApprovalRule,
null,
state,
[{ type: mutationTypes.REQUEST_LICENSE_CHECK_APPROVAL_RULE }],
[],
)
.then(done)
.catch(done.fail);
});
});
describe('receiveLicenseCheckApprovalRuleSuccess', () => {
it('commits REQUEST_LICENSE_CHECK_APPROVAL_RULE', done => {
const hasLicenseCheckApprovalRule = true;
testAction(
actions.receiveLicenseCheckApprovalRuleSuccess,
{ hasLicenseCheckApprovalRule },
state,
[
{
type: mutationTypes.RECEIVE_LICENSE_CHECK_APPROVAL_RULE_SUCCESS,
payload: { hasLicenseCheckApprovalRule },
},
],
[],
)
.then(done)
.catch(done.fail);
});
});
describe('receiveLicenseCheckApprovalRuleError', () => {
it('commits RECEIVE_LICENSE_CHECK_APPROVAL_RULE_ERROR', done => {
const error = new Error('Error');
testAction(
actions.receiveLicenseCheckApprovalRuleError,
error,
state,
[{ type: mutationTypes.RECEIVE_LICENSE_CHECK_APPROVAL_RULE_ERROR, payload: error }],
[],
)
.then(done)
.catch(done.fail);
});
});
describe('requestParsedLicenseReport', () => { describe('requestParsedLicenseReport', () => {
it(`should commit ${mutationTypes.REQUEST_PARSED_LICENSE_REPORT}`, done => { it(`should commit ${mutationTypes.REQUEST_PARSED_LICENSE_REPORT}`, done => {
testAction( testAction(
......
...@@ -153,6 +153,54 @@ describe('License store mutations', () => { ...@@ -153,6 +153,54 @@ describe('License store mutations', () => {
}); });
}); });
describe('REQUEST_LICENSE_CHECK_APPROVAL_RULE', () => {
it('sets isLoadingLicenseCheckApprovalRule to true', () => {
store.replaceState({
...store.state,
licenseManagement: {
isLoadingLicenseCheckApprovalRule: true,
},
});
store.commit(`licenseManagement/${types.REQUEST_LICENSE_CHECK_APPROVAL_RULE}`);
expect(store.state.licenseManagement.isLoadingLicenseCheckApprovalRule).toBe(true);
});
});
describe('RECEIVE_LICENSE_CHECK_APPROVAL_RULE_SUCCESS', () => {
it('sets isLoadingLicenseCheckApprovalRule to false and hasLicenseCheckApprovalRule to true', () => {
store.replaceState({
...store.state,
licenseManagement: {
isLoadingLicenseCheckApprovalRule: true,
},
});
store.commit(`licenseManagement/${types.RECEIVE_LICENSE_CHECK_APPROVAL_RULE_SUCCESS}`, {
hasLicenseCheckApprovalRule: true,
});
expect(store.state.licenseManagement.isLoadingLicenseCheckApprovalRule).toBe(false);
expect(store.state.licenseManagement.hasLicenseCheckApprovalRule).toBe(true);
});
});
describe('RECEIVE_LICENSE_CHECK_APPROVAL_RULE_ERROR', () => {
it('sets isLoadingLicenseCheckApprovalRule to false', () => {
store.replaceState({
...store.state,
licenseManagement: {
isLoadingLicenseCheckApprovalRule: true,
},
});
store.commit(`licenseManagement/${types.RECEIVE_LICENSE_CHECK_APPROVAL_RULE_ERROR}`);
expect(store.state.licenseManagement.isLoadingLicenseCheckApprovalRule).toBe(false);
});
});
describe('RECEIVE_MANAGED_LICENSES_SUCCESS', () => { describe('RECEIVE_MANAGED_LICENSES_SUCCESS', () => {
it('sets isLoadingManagedLicenses and loadManagedLicensesError to false and saves managed licenses', () => { it('sets isLoadingManagedLicenses and loadManagedLicensesError to false and saves managed licenses', () => {
store.replaceState({ store.replaceState({
......
...@@ -13524,6 +13524,11 @@ msgstr "" ...@@ -13524,6 +13524,11 @@ msgstr ""
msgid "LicenseCompliance|License Approvals" msgid "LicenseCompliance|License Approvals"
msgstr "" msgstr ""
msgid "LicenseCompliance|License Compliance detected %d license and policy violation for the source branch only"
msgid_plural "LicenseCompliance|License Compliance detected %d licenses and policy violations for the source branch only"
msgstr[0] ""
msgstr[1] ""
msgid "LicenseCompliance|License Compliance detected %d license and policy violation for the source branch only; approval required" msgid "LicenseCompliance|License Compliance detected %d license and policy violation for the source branch only; approval required"
msgid_plural "LicenseCompliance|License Compliance detected %d licenses and policy violations for the source branch only; approval required" msgid_plural "LicenseCompliance|License Compliance detected %d licenses and policy violations for the source branch only; approval required"
msgstr[0] "" msgstr[0] ""
...@@ -13539,6 +13544,11 @@ msgid_plural "LicenseCompliance|License Compliance detected %d new licenses" ...@@ -13539,6 +13544,11 @@ msgid_plural "LicenseCompliance|License Compliance detected %d new licenses"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "LicenseCompliance|License Compliance detected %d new license and policy violation"
msgid_plural "LicenseCompliance|License Compliance detected %d new licenses and policy violations"
msgstr[0] ""
msgstr[1] ""
msgid "LicenseCompliance|License Compliance detected %d new license and policy violation; approval required" msgid "LicenseCompliance|License Compliance detected %d new license and policy violation; approval required"
msgid_plural "LicenseCompliance|License Compliance detected %d new licenses and policy violations; approval required" msgid_plural "LicenseCompliance|License Compliance detected %d new licenses and policy violations; approval required"
msgstr[0] "" msgstr[0] ""
...@@ -27961,6 +27971,9 @@ msgstr "" ...@@ -27961,6 +27971,9 @@ msgstr ""
msgid "mrWidget|You can merge this merge request manually using the" msgid "mrWidget|You can merge this merge request manually using the"
msgstr "" msgstr ""
msgid "mrWidget|You can only merge once the denied license is removed"
msgstr ""
msgid "mrWidget|Your password" msgid "mrWidget|Your password"
msgstr "" msgstr ""
......
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