Commit ec9d067d authored by Jacques Erasmus's avatar Jacques Erasmus

Merge branch '327751-code-quality-widget-status-not-found' into 'master'

Render base path error based on report status

See merge request gitlab-org/gitlab!67370
parents ef4d93f8 6c70491d
......@@ -12,19 +12,10 @@ export default {
ReportSection,
},
props: {
headPath: {
type: String,
required: true,
},
headBlobPath: {
type: String,
required: true,
},
basePath: {
type: String,
required: false,
default: null,
},
baseBlobPath: {
type: String,
required: false,
......@@ -52,8 +43,6 @@ export default {
},
created() {
this.setPaths({
basePath: this.basePath,
headPath: this.headPath,
baseBlobPath: this.baseBlobPath,
headBlobPath: this.headBlobPath,
reportsPath: this.codequalityReportsPath,
......
import pollUntilComplete from '~/lib/utils/poll_until_complete';
import { STATUS_NOT_FOUND } from '../../constants';
import * as types from './mutation_types';
import { parseCodeclimateMetrics } from './utils/codequality_parser';
......@@ -7,11 +8,11 @@ export const setPaths = ({ commit }, paths) => commit(types.SET_PATHS, paths);
export const fetchReports = ({ state, dispatch, commit }) => {
commit(types.REQUEST_REPORTS);
if (!state.basePath) {
return dispatch('receiveReportsError');
}
return pollUntilComplete(state.reportsPath)
.then(({ data }) => {
if (data.status === STATUS_NOT_FOUND) {
return dispatch('receiveReportsError', data);
}
return dispatch('receiveReportsSuccess', {
newIssues: parseCodeclimateMetrics(data.new_errors, state.headBlobPath),
resolvedIssues: parseCodeclimateMetrics(data.resolved_errors, state.baseBlobPath),
......
import { spriteIcon } from '~/lib/utils/common_utils';
import { sprintf, __, s__, n__ } from '~/locale';
import { LOADING, ERROR, SUCCESS } from '../../constants';
import { LOADING, ERROR, SUCCESS, STATUS_NOT_FOUND } from '../../constants';
export const hasCodequalityIssues = (state) =>
Boolean(state.newIssues?.length || state.resolvedIssues?.length);
......@@ -42,7 +42,7 @@ export const codequalityText = (state) => {
};
export const codequalityPopover = (state) => {
if (state.headPath && !state.basePath) {
if (state.status === STATUS_NOT_FOUND) {
return {
title: s__('ciReport|Base pipeline codequality artifact not found'),
content: sprintf(
......
......@@ -2,8 +2,6 @@ import * as types from './mutation_types';
export default {
[types.SET_PATHS](state, paths) {
state.basePath = paths.basePath;
state.headPath = paths.headPath;
state.baseBlobPath = paths.baseBlobPath;
state.headBlobPath = paths.headBlobPath;
state.reportsPath = paths.reportsPath;
......@@ -14,6 +12,7 @@ export default {
},
[types.RECEIVE_REPORTS_SUCCESS](state, data) {
state.hasError = false;
state.status = '';
state.statusReason = '';
state.isLoading = false;
state.newIssues = data.newIssues;
......@@ -22,6 +21,7 @@ export default {
[types.RECEIVE_REPORTS_ERROR](state, error) {
state.isLoading = false;
state.hasError = true;
state.status = error?.status || '';
state.statusReason = error?.response?.data?.status_reason;
},
};
export default () => ({
basePath: null,
headPath: null,
reportsPath: null,
baseBlobPath: null,
......@@ -8,6 +6,7 @@ export default () => ({
isLoading: false,
hasError: false,
status: '',
statusReason: '',
newIssues: [],
......
......@@ -12,6 +12,7 @@ export const SUCCESS = 'SUCCESS';
export const STATUS_FAILED = 'failed';
export const STATUS_SUCCESS = 'success';
export const STATUS_NEUTRAL = 'neutral';
export const STATUS_NOT_FOUND = 'not_found';
export const ICON_WARNING = 'warning';
export const ICON_SUCCESS = 'success';
......
......@@ -150,7 +150,7 @@ export default {
);
},
shouldRenderCodeQuality() {
return this.mr?.codeclimate?.head_path;
return this.mr?.codequalityReportsPath;
},
shouldRenderRelatedLinks() {
return Boolean(this.mr.relatedLinks) && !this.mr.isNothingToMergeState;
......@@ -496,8 +496,6 @@ export default {
<!-- <extensions-container :mr="mr" /> -->
<grouped-codequality-reports-app
v-if="shouldRenderCodeQuality"
:base-path="mr.codeclimate.base_path"
:head-path="mr.codeclimate.head_path"
:head-blob-path="mr.headBlobPath"
:base-blob-path="mr.baseBlobPath"
:codequality-reports-path="mr.codequalityReportsPath"
......
......@@ -261,7 +261,6 @@ export default class MergeRequestStore {
this.baseBlobPath = blobPath.base_path || '';
this.codequalityReportsPath = data.codequality_reports_path;
this.codequalityHelpPath = data.codequality_help_path;
this.codeclimate = data.codeclimate;
// Security reports
this.sastComparisonPath = data.sast_comparison_path;
......
......@@ -307,8 +307,6 @@ export default {
<blocking-merge-requests-report :mr="mr" />
<grouped-codequality-reports-app
v-if="shouldRenderCodeQuality"
:base-path="mr.codeclimate.base_path"
:head-path="mr.codeclimate.head_path"
:head-blob-path="mr.headBlobPath"
:base-blob-path="mr.baseBlobPath"
:codequality-reports-path="mr.codequalityReportsPath"
......
......@@ -3,6 +3,7 @@ import Vuex from 'vuex';
import CodequalityIssueBody from '~/reports/codequality_report/components/codequality_issue_body.vue';
import GroupedCodequalityReportsApp from '~/reports/codequality_report/grouped_codequality_reports_app.vue';
import { getStoreConfig } from '~/reports/codequality_report/store';
import { STATUS_NOT_FOUND } from '~/reports/constants';
import { parsedReportIssues } from './mock_data';
const localVue = createLocalVue();
......@@ -14,8 +15,6 @@ describe('Grouped code quality reports app', () => {
const PATHS = {
codequalityHelpPath: 'codequality_help.html',
basePath: 'base.json',
headPath: 'head.json',
baseBlobPath: 'base/blob/path/',
headBlobPath: 'head/blob/path/',
};
......@@ -127,21 +126,6 @@ describe('Grouped code quality reports app', () => {
});
});
describe('when there is a head report but no base report', () => {
beforeEach(() => {
mockStore.state.basePath = null;
mockStore.state.hasError = true;
});
it('renders error text', () => {
expect(findWidget().text()).toContain('Failed to load codeclimate report');
});
it('renders a help icon with more information', () => {
expect(findWidget().find('[data-testid="question-icon"]').exists()).toBe(true);
});
});
describe('on error', () => {
beforeEach(() => {
mockStore.state.hasError = true;
......@@ -154,5 +138,15 @@ describe('Grouped code quality reports app', () => {
it('does not render a help icon', () => {
expect(findWidget().find('[data-testid="question-icon"]').exists()).toBe(false);
});
describe('when base report was not found', () => {
beforeEach(() => {
mockStore.state.status = STATUS_NOT_FOUND;
});
it('renders a help icon with more information', () => {
expect(findWidget().find('[data-testid="question-icon"]').exists()).toBe(true);
});
});
});
});
......@@ -5,6 +5,7 @@ import axios from '~/lib/utils/axios_utils';
import createStore from '~/reports/codequality_report/store';
import * as actions from '~/reports/codequality_report/store/actions';
import * as types from '~/reports/codequality_report/store/mutation_types';
import { STATUS_NOT_FOUND } from '~/reports/constants';
import { reportIssues, parsedReportIssues } from '../mock_data';
const pollInterval = 123;
......@@ -24,8 +25,6 @@ describe('Codequality Reports actions', () => {
describe('setPaths', () => {
it('should commit SET_PATHS mutation', (done) => {
const paths = {
basePath: 'basePath',
headPath: 'headPath',
baseBlobPath: 'baseBlobPath',
headBlobPath: 'headBlobPath',
reportsPath: 'reportsPath',
......@@ -49,7 +48,6 @@ describe('Codequality Reports actions', () => {
beforeEach(() => {
localState.reportsPath = endpoint;
localState.basePath = '/base/path';
mock = new MockAdapter(axios);
});
......@@ -92,16 +90,17 @@ describe('Codequality Reports actions', () => {
});
});
describe('with no base path', () => {
describe('when base report is not found', () => {
it('commits REQUEST_REPORTS and dispatches receiveReportsError', (done) => {
localState.basePath = null;
const data = { status: STATUS_NOT_FOUND };
mock.onGet(`${TEST_HOST}/codequality_reports.json`).reply(200, data);
testAction(
actions.fetchReports,
null,
localState,
[{ type: types.REQUEST_REPORTS }],
[{ type: 'receiveReportsError' }],
[{ type: 'receiveReportsError', payload: data }],
done,
);
});
......
import createStore from '~/reports/codequality_report/store';
import * as getters from '~/reports/codequality_report/store/getters';
import { LOADING, ERROR, SUCCESS } from '~/reports/constants';
import { LOADING, ERROR, SUCCESS, STATUS_NOT_FOUND } from '~/reports/constants';
describe('Codequality reports store getters', () => {
let localState;
......@@ -76,10 +76,9 @@ describe('Codequality reports store getters', () => {
});
describe('codequalityPopover', () => {
describe('when head report is available but base report is not', () => {
describe('when base report is not available', () => {
it('returns a popover with a documentation link', () => {
localState.headPath = 'head.json';
localState.basePath = undefined;
localState.status = STATUS_NOT_FOUND;
localState.helpPath = 'codequality_help.html';
expect(getters.codequalityPopover(localState).title).toEqual(
......
import createStore from '~/reports/codequality_report/store';
import mutations from '~/reports/codequality_report/store/mutations';
import { STATUS_NOT_FOUND } from '~/reports/constants';
describe('Codequality Reports mutations', () => {
let localState;
......@@ -12,24 +13,18 @@ describe('Codequality Reports mutations', () => {
describe('SET_PATHS', () => {
it('sets paths to given values', () => {
const basePath = 'base.json';
const headPath = 'head.json';
const baseBlobPath = 'base/blob/path/';
const headBlobPath = 'head/blob/path/';
const reportsPath = 'reports.json';
const helpPath = 'help.html';
mutations.SET_PATHS(localState, {
basePath,
headPath,
baseBlobPath,
headBlobPath,
reportsPath,
helpPath,
});
expect(localState.basePath).toEqual(basePath);
expect(localState.headPath).toEqual(headPath);
expect(localState.baseBlobPath).toEqual(baseBlobPath);
expect(localState.headBlobPath).toEqual(headBlobPath);
expect(localState.reportsPath).toEqual(reportsPath);
......@@ -58,9 +53,10 @@ describe('Codequality Reports mutations', () => {
expect(localState.hasError).toEqual(false);
});
it('clears statusReason', () => {
it('clears status and statusReason', () => {
mutations.RECEIVE_REPORTS_SUCCESS(localState, {});
expect(localState.status).toEqual('');
expect(localState.statusReason).toEqual('');
});
......@@ -86,6 +82,13 @@ describe('Codequality Reports mutations', () => {
expect(localState.hasError).toEqual(true);
});
it('sets status based on error object', () => {
const error = { status: STATUS_NOT_FOUND };
mutations.RECEIVE_REPORTS_ERROR(localState, error);
expect(localState.status).toEqual(error.status);
});
it('sets statusReason to string from error response data', () => {
const data = { status_reason: 'This merge request does not have codequality reports' };
const error = { response: { data } };
......
......@@ -234,14 +234,11 @@ export default {
can_revert_on_current_merge_request: true,
can_cherry_pick_on_current_merge_request: true,
},
codeclimate: {
head_path: 'head.json',
base_path: 'base.json',
},
blob_path: {
base_path: 'blob_path',
head_path: 'blob_path',
},
codequality_reports_path: 'codequality_reports.json',
codequality_help_path: 'code_quality.html',
target_branch_path: '/root/acets-app/branches/main',
source_branch_path: '/root/acets-app/branches/daaaa',
......
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