Commit d2f072da authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch '342897-update-compliance-report-local-resolver' into 'master'

Update compliance report local resolver to match new format

See merge request gitlab-org/gitlab!82402
parents 158e92ec ac325495
......@@ -115,21 +115,21 @@ export default {
this.updateUrlQuery({ ...this.urlQuery, sort: this.sortParam });
},
toggleDrawer(rows) {
const { mergeRequest, project } = rows[0] || {};
const { mergeRequest } = rows[0] || {};
if (!mergeRequest || this.isCurrentDrawer(mergeRequest)) {
this.closeDrawer();
} else {
this.openDrawer(mergeRequest, project);
this.openDrawer(mergeRequest);
}
},
isCurrentDrawer(mergeRequest) {
return this.showDrawer && mergeRequest.id === this.drawerMergeRequest.id;
},
openDrawer(mergeRequest, project) {
openDrawer(mergeRequest) {
this.showDrawer = true;
this.drawerMergeRequest = mergeRequest;
this.drawerProject = project;
this.drawerProject = mergeRequest.project;
},
closeDrawer() {
this.showDrawer = false;
......@@ -161,7 +161,7 @@ export default {
},
fields: [
{
key: 'severity',
key: 'severityLevel',
label: __('Severity'),
thClass: thWidthClass(10),
sortable: true,
......@@ -259,8 +259,8 @@ export default {
@row-selected="toggleDrawer"
@sort-changed="handleSortChanged"
>
<template #cell(severity)="{ item: { severity } }">
<severity-badge class="gl-reset-text-align!" :severity="severity" />
<template #cell(severityLevel)="{ item: { severityLevel } }">
<severity-badge class="gl-reset-text-align!" :severity="severityLevel" />
</template>
<template #cell(violationReason)="{ item: { reason, violatingUser } }">
<violation-reason :reason="reason" :user="violatingUser" />
......
......@@ -38,11 +38,11 @@ export default {
},
computed: {
defaultStartDate() {
const startDate = this.defaultQuery.createdAfter;
const startDate = this.defaultQuery.mergedAfter;
return startDate ? parsePikadayDate(startDate) : getDateInPast(CURRENT_DATE, 30);
},
defaultEndDate() {
const endDate = this.defaultQuery.createdBefore;
const endDate = this.defaultQuery.mergedBefore;
return endDate ? parsePikadayDate(endDate) : CURRENT_DATE;
},
},
......@@ -74,8 +74,8 @@ export default {
},
dateRangeChanged({ startDate = this.defaultStartDate, endDate = this.defaultEndDate }) {
this.updateFilter({
createdAfter: pikadayToString(startDate),
createdBefore: pikadayToString(endDate),
mergedAfter: pikadayToString(startDate),
mergedBefore: pikadayToString(endDate),
});
},
updateFilter(query) {
......
<script>
import { MERGE_REQUEST_VIOLATION_REASONS, MERGE_REQUEST_VIOLATION_MESSAGES } from '../../constants';
import { MERGE_REQUEST_VIOLATION_MESSAGES } from '../../constants';
import UserAvatar from '../shared/user_avatar.vue';
export default {
......@@ -8,8 +8,9 @@ export default {
},
props: {
reason: {
type: Number,
type: String,
required: true,
validator: (reason) => Object.keys(MERGE_REQUEST_VIOLATION_MESSAGES).includes(reason),
},
user: {
type: Object,
......@@ -18,11 +19,8 @@ export default {
},
},
computed: {
violation() {
return MERGE_REQUEST_VIOLATION_REASONS[this.reason];
},
violationMessage() {
return MERGE_REQUEST_VIOLATION_MESSAGES[this.violation];
return MERGE_REQUEST_VIOLATION_MESSAGES[this.reason];
},
},
};
......
......@@ -16,27 +16,14 @@ export const GRAPHQL_PAGE_SIZE = 20;
export const COMPLIANCE_DRAWER_CONTAINER_CLASS = '.content-wrapper';
const VIOLATION_TYPE_APPROVED_BY_AUTHOR = 'approved_by_author';
const VIOLATION_TYPE_APPROVED_BY_COMMITTER = 'approved_by_committer';
const VIOLATION_TYPE_APPROVED_BY_INSUFFICIENT_USERS = 'approved_by_insufficient_users';
export const MERGE_REQUEST_VIOLATION_REASONS = {
0: VIOLATION_TYPE_APPROVED_BY_AUTHOR,
1: VIOLATION_TYPE_APPROVED_BY_COMMITTER,
2: VIOLATION_TYPE_APPROVED_BY_INSUFFICIENT_USERS,
};
const APPROVED_BY_COMMITTER = 'APPROVED_BY_COMMITTER';
const APPROVED_BY_INSUFFICIENT_USERS = 'APPROVED_BY_INSUFFICIENT_USERS';
const APPROVED_BY_MERGE_REQUEST_AUTHOR = 'APPROVED_BY_MERGE_REQUEST_AUTHOR';
export const MERGE_REQUEST_VIOLATION_MESSAGES = {
[VIOLATION_TYPE_APPROVED_BY_AUTHOR]: s__('ComplianceReport|Approved by author'),
[VIOLATION_TYPE_APPROVED_BY_COMMITTER]: s__('ComplianceReport|Approved by committer'),
[VIOLATION_TYPE_APPROVED_BY_INSUFFICIENT_USERS]: s__('ComplianceReport|Less than 2 approvers'),
};
export const MERGE_REQUEST_VIOLATION_SEVERITY_LEVELS = {
1: 'high',
2: 'medium',
3: 'low',
4: 'info',
[APPROVED_BY_COMMITTER]: s__('ComplianceReport|Approved by committer'),
[APPROVED_BY_INSUFFICIENT_USERS]: s__('ComplianceReport|Less than 2 approvers'),
[APPROVED_BY_MERGE_REQUEST_AUTHOR]: s__('ComplianceReport|Approved by author'),
};
export const DEFAULT_SORT = 'SEVERITY_DESC';
export const DEFAULT_SORT = 'SEVERITY_LEVEL_DESC';
......@@ -21,7 +21,7 @@ query getComplianceViolations(
mergeRequestViolations {
nodes {
id
severity
severityLevel
reason
violatingUser {
id
......@@ -42,7 +42,7 @@ query getComplianceViolations(
avatarUrl
webUrl
}
mergedBy {
mergeUser {
id
name
username
......@@ -76,24 +76,24 @@ query getComplianceViolations(
webUrl
}
}
reference
ref
fullRef: reference(full: true)
sourceBranch
sourceBranchExists
targetBranch
targetBranchExists
}
project {
id
avatarUrl
name
webUrl
complianceFrameworks {
nodes {
id
name
description
color
project {
id
avatarUrl
name
webUrl
complianceFrameworks {
nodes {
id
name
description
color
}
}
}
}
......
import { MERGE_REQUEST_VIOLATION_SEVERITY_LEVELS } from '../constants';
export const mapViolations = (nodes = []) => {
return nodes.map((node) => ({
...node,
......@@ -8,11 +6,13 @@ export const mapViolations = (nodes = []) => {
committers: node.mergeRequest.committers?.nodes || [],
approvedByUsers: node.mergeRequest.approvedBy?.nodes || [],
participants: node.mergeRequest.participants?.nodes || [],
// TODO: Once the legacy dashboard is removed (https://gitlab.com/gitlab-org/gitlab/-/issues/346266) we can update the drawer to use the new attributes and remove these 2 mappings
reference: node.mergeRequest.ref,
mergedBy: node.mergeRequest.mergeUser,
project: {
...node.mergeRequest.project,
complianceFramework: node.mergeRequest.project?.complianceFrameworks?.nodes[0] || null,
},
},
project: {
...node.project,
complianceFramework: node.project?.complianceFrameworks?.nodes[0] || null,
},
severity: MERGE_REQUEST_VIOLATION_SEVERITY_LEVELS[node.severity],
}));
};
......@@ -15,8 +15,8 @@ export default {
{
__typename: 'MergeRequestViolation',
id: 1,
severity: 1,
reason: 1,
severityLevel: 'HIGH',
reason: 'APPROVED_BY_COMMITTER',
violatingUser: {
__typename: 'Violator',
id: 50,
......@@ -42,7 +42,7 @@ export default {
'https://secure.gravatar.com/avatar/7ff9b8111da2e2109e7b66f37aa632cc?s=80&d=identicon',
webUrl: 'https://gdk.localhost:3443/user6',
},
mergedBy: {
mergeUser: {
__typename: 'MergedBy',
id: 50,
name: 'John Doe6',
......@@ -93,37 +93,37 @@ export default {
],
},
fullRef: 'gitlab-shell!1',
reference: '!1',
ref: '!1',
sourceBranch: 'ut-171ad4e263',
sourceBranchExists: false,
targetBranch: 'master',
targetBranchExists: true,
},
project: {
__typename: 'Project',
id: 1,
avatarUrl: null,
name: 'Gitlab Shell',
webUrl: 'https://gdk.localhost:3443/gitlab-org/gitlab-shell',
complianceFrameworks: {
__typename: 'ComplianceFrameworks',
nodes: [
{
__typename: 'ComplianceFrameworks',
id: 1,
name: 'GDPR',
description: 'General Data Protection Regulation',
color: '#009966',
},
],
project: {
__typename: 'Project',
id: 1,
avatarUrl: null,
name: 'Gitlab Shell',
webUrl: 'https://gdk.localhost:3443/gitlab-org/gitlab-shell',
complianceFrameworks: {
__typename: 'ComplianceFrameworks',
nodes: [
{
__typename: 'ComplianceFrameworks',
id: 1,
name: 'GDPR',
description: 'General Data Protection Regulation',
color: '#009966',
},
],
},
},
},
},
{
__typename: 'MergeRequestViolation',
id: 2,
severity: 2,
reason: 2,
severityLevel: 'HIGH',
reason: 'APPROVED_BY_INSUFFICIENT_USERS',
violatingUser: {
__typename: 'Violator',
id: 50,
......@@ -149,7 +149,7 @@ export default {
'https://secure.gravatar.com/avatar/7ff9b8111da2e2109e7b66f37aa632cc?s=80&d=identicon',
webUrl: 'https://gdk.localhost:3443/user6',
},
mergedBy: {
mergeUser: {
__typename: 'MergedBy',
id: 50,
name: 'John Doe6',
......@@ -191,29 +191,29 @@ export default {
],
},
fullRef: 'gitlab-test!2',
reference: '!2',
ref: '!2',
sourceBranch: 'ut-171ad4e264',
sourceBranchExists: false,
targetBranch: 'master',
targetBranchExists: true,
},
project: {
__typename: 'Project',
id: 2,
avatarUrl: null,
name: 'Gitlab Test',
webUrl: 'https://gdk.localhost:3443/gitlab-org/gitlab-test',
complianceFrameworks: {
__typename: 'ComplianceFrameworks',
nodes: [
{
__typename: 'ComplianceFrameworks',
id: 2,
name: 'SOX',
description: 'A framework',
color: '#00FF00',
},
],
project: {
__typename: 'Project',
id: 2,
avatarUrl: null,
name: 'Gitlab Test',
webUrl: 'https://gdk.localhost:3443/gitlab-org/gitlab-test',
complianceFrameworks: {
__typename: 'ComplianceFrameworks',
nodes: [
{
__typename: 'ComplianceFrameworks',
id: 2,
name: 'SOX',
description: 'A framework',
color: '#00FF00',
},
],
},
},
},
},
......
......@@ -28,7 +28,7 @@ describe('MergeRequestDrawer component', () => {
targetBranch: null,
targetBranchUri: null,
},
project: defaultData.project,
project: defaultData.mergeRequest.project,
};
const findTitle = () => wrapper.findByTestId('dashboard-drawer-title');
......
......@@ -30,12 +30,12 @@ describe('ComplianceReport component', () => {
const mergeCommitsCsvExportPath = '/csv';
const groupPath = 'group-path';
const createdAfter = '2021-11-16';
const createdBefore = '2021-12-15';
const mergedAfter = '2021-11-16';
const mergedBefore = '2021-12-15';
const defaultQuery = {
projectIds: ['20'],
createdAfter,
createdBefore,
mergedAfter,
mergedBefore,
sort: DEFAULT_SORT,
};
const mockGraphQlError = new Error('GraphQL networkError');
......@@ -237,9 +237,9 @@ describe('ComplianceReport component', () => {
});
it('renders the violation severity badge', () => {
const { severity } = mapViolations(mockResolver().mergeRequestViolations.nodes)[0];
const { severityLevel } = mapViolations(mockResolver().mergeRequestViolations.nodes)[0];
expect(findSeverityBadge().props()).toStrictEqual({ severity });
expect(findSeverityBadge().props()).toStrictEqual({ severity: severityLevel });
});
it('renders the violation reason', () => {
......@@ -289,7 +289,7 @@ describe('ComplianceReport component', () => {
stripTypenames(drawerData.mergeRequest),
);
expect(findMergeRequestDrawer().props('project')).toStrictEqual(
stripTypenames(drawerData.project),
stripTypenames(drawerData.mergeRequest.project),
);
});
......@@ -313,7 +313,7 @@ describe('ComplianceReport component', () => {
stripTypenames(drawerData.mergeRequest),
);
expect(findMergeRequestDrawer().props('project')).toStrictEqual(
stripTypenames(drawerData.project),
stripTypenames(drawerData.mergeRequest.project),
);
});
});
......@@ -335,7 +335,7 @@ describe('ComplianceReport component', () => {
});
describe('when the filters changed', () => {
const query = { createdAfter, createdBefore, projectIds: [1, 2, 3] };
const query = { mergedAfter, mergedBefore, projectIds: [1, 2, 3] };
beforeEach(() => {
return findViolationFilter().vm.$emit('filters-changed', query);
......
......@@ -21,8 +21,8 @@ describe('ViolationFilter component', () => {
const startDate = getDateInPast(CURRENT_DATE, 20);
const endDate = getDateInPast(CURRENT_DATE, 4);
const dateRangeQuery = {
createdAfter: pikadayToString(startDate),
createdBefore: pikadayToString(endDate),
mergedAfter: pikadayToString(startDate),
mergedBefore: pikadayToString(endDate),
};
const defaultProjects = createDefaultProjects(2);
const projectsResponse = createDefaultProjectsResponse(defaultProjects);
......@@ -119,7 +119,7 @@ describe('ViolationFilter component', () => {
});
describe('with a default query', () => {
const defaultQuery = { projectIds, createdAfter: '2022-01-01', createdBefore: '2022-01-31' };
const defaultQuery = { projectIds, mergedAfter: '2022-01-01', mergedBefore: '2022-01-31' };
beforeEach(() => {
createComponent({ defaultQuery });
......
......@@ -2,18 +2,14 @@ import { shallowMount } from '@vue/test-utils';
import ViolationReason from 'ee/compliance_dashboard/components/violations/reason.vue';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import UserAvatar from 'ee/compliance_dashboard/components/shared/user_avatar.vue';
import {
MERGE_REQUEST_VIOLATION_MESSAGES,
MERGE_REQUEST_VIOLATION_REASONS,
} from 'ee/compliance_dashboard/constants';
import { MERGE_REQUEST_VIOLATION_MESSAGES } from 'ee/compliance_dashboard/constants';
import { createUser } from '../../mock_data';
describe('ViolationReason component', () => {
let wrapper;
const user = convertObjectPropsToCamelCase(createUser(1));
const reasons = Object.keys(MERGE_REQUEST_VIOLATION_MESSAGES);
const getViolationMessage = (reason) =>
MERGE_REQUEST_VIOLATION_MESSAGES[MERGE_REQUEST_VIOLATION_REASONS[reason]];
const findAvatar = () => wrapper.findComponent(UserAvatar);
const createComponent = (propsData = {}) => {
......@@ -25,30 +21,22 @@ describe('ViolationReason component', () => {
});
describe('violation message', () => {
it.each`
reason | message
${0} | ${getViolationMessage(0)}
${1} | ${getViolationMessage(1)}
${2} | ${getViolationMessage(2)}
`(
'renders the violation message "$message" for the reason code $reason',
({ reason, message }) => {
createComponent({ reason });
expect(wrapper.text()).toContain(message);
},
);
it.each(reasons)('renders the violation message for the reason %s', (reason) => {
createComponent({ reason });
expect(wrapper.text()).toContain(MERGE_REQUEST_VIOLATION_MESSAGES[reason]);
});
});
describe('violation user', () => {
it('does not render a user avatar by default', () => {
createComponent({ reason: 0 });
createComponent({ reason: reasons[0] });
expect(findAvatar().exists()).toBe(false);
});
it('renders a user avatar when the user prop is set', () => {
createComponent({ reason: 0, user });
createComponent({ reason: reasons[0], user });
expect(findAvatar().props('user')).toBe(user);
});
......
import { mapViolations } from 'ee/compliance_dashboard/graphql/mappers';
import resolvers from 'ee/compliance_dashboard/graphql/resolvers';
import { MERGE_REQUEST_VIOLATION_SEVERITY_LEVELS } from 'ee/compliance_dashboard/constants';
describe('mapViolations', () => {
const mockViolations = resolvers.Query.group().mergeRequestViolations.nodes;
const severityLevels = Object.keys(MERGE_REQUEST_VIOLATION_SEVERITY_LEVELS).map(Number);
it.each(severityLevels)(
'maps to the expected severity level when the violation severity number is %s',
(severity) => {
const { severity: severityLevel } = mapViolations([{ ...mockViolations[0], severity }])[0];
it('returns the expected result', () => {
const { mergeRequest } = mapViolations([{ ...mockViolations[0] }])[0];
expect(severityLevel).toBe(MERGE_REQUEST_VIOLATION_SEVERITY_LEVELS[severity]);
},
);
expect(mergeRequest).toMatchObject({
reference: mergeRequest.ref,
mergedBy: mergeRequest.mergeUser,
});
});
});
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