Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-07-14 18:09:05 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-07-14 18:09:05 +0300
commit66bd1f0fdcaf84fa3412c70d7962b49eb8a48fde (patch)
tree23f451b4e60a6e28bcc15043d7756bb27dcc2970 /app/assets/javascripts/reports
parent49089d4fb1f5c17328ac61c955d95a68c6d4d545 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/reports')
-rw-r--r--app/assets/javascripts/reports/codequality_report/store/actions.js30
-rw-r--r--app/assets/javascripts/reports/codequality_report/store/getters.js58
-rw-r--r--app/assets/javascripts/reports/codequality_report/store/index.js16
-rw-r--r--app/assets/javascripts/reports/codequality_report/store/mutation_types.js5
-rw-r--r--app/assets/javascripts/reports/codequality_report/store/mutations.js24
-rw-r--r--app/assets/javascripts/reports/codequality_report/store/state.js15
-rw-r--r--app/assets/javascripts/reports/codequality_report/store/utils/codequality_comparison.js41
-rw-r--r--app/assets/javascripts/reports/codequality_report/workers/codequality_comparison_worker.js28
8 files changed, 217 insertions, 0 deletions
diff --git a/app/assets/javascripts/reports/codequality_report/store/actions.js b/app/assets/javascripts/reports/codequality_report/store/actions.js
new file mode 100644
index 00000000000..bf84d27b5ea
--- /dev/null
+++ b/app/assets/javascripts/reports/codequality_report/store/actions.js
@@ -0,0 +1,30 @@
+import axios from '~/lib/utils/axios_utils';
+import * as types from './mutation_types';
+import { parseCodeclimateMetrics, doCodeClimateComparison } from './utils/codequality_comparison';
+
+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 Promise.all([axios.get(state.headPath), axios.get(state.basePath)])
+ .then(results =>
+ doCodeClimateComparison(
+ parseCodeclimateMetrics(results[0].data, state.headBlobPath),
+ parseCodeclimateMetrics(results[1].data, state.baseBlobPath),
+ ),
+ )
+ .then(data => dispatch('receiveReportsSuccess', data))
+ .catch(() => dispatch('receiveReportsError'));
+};
+
+export const receiveReportsSuccess = ({ commit }, data) => {
+ commit(types.RECEIVE_REPORTS_SUCCESS, data);
+};
+
+export const receiveReportsError = ({ commit }) => {
+ commit(types.RECEIVE_REPORTS_ERROR);
+};
diff --git a/app/assets/javascripts/reports/codequality_report/store/getters.js b/app/assets/javascripts/reports/codequality_report/store/getters.js
new file mode 100644
index 00000000000..5df58c7f85f
--- /dev/null
+++ b/app/assets/javascripts/reports/codequality_report/store/getters.js
@@ -0,0 +1,58 @@
+import { LOADING, ERROR, SUCCESS } from '../../constants';
+import { sprintf, __, s__, n__ } from '~/locale';
+
+export const hasCodequalityIssues = state =>
+ Boolean(state.newIssues?.length || state.resolvedIssues?.length);
+
+export const codequalityStatus = state => {
+ if (state.isLoading) {
+ return LOADING;
+ }
+ if (state.hasError) {
+ return ERROR;
+ }
+
+ return SUCCESS;
+};
+
+export const codequalityText = state => {
+ const { newIssues, resolvedIssues } = state;
+ const text = [];
+
+ if (!newIssues.length && !resolvedIssues.length) {
+ text.push(s__('ciReport|No changes to code quality'));
+ } else {
+ text.push(s__('ciReport|Code quality'));
+
+ if (resolvedIssues.length) {
+ text.push(n__(' improved on %d point', ' improved on %d points', resolvedIssues.length));
+ }
+
+ if (newIssues.length && resolvedIssues.length) {
+ text.push(__(' and'));
+ }
+
+ if (newIssues.length) {
+ text.push(n__(' degraded on %d point', ' degraded on %d points', newIssues.length));
+ }
+ }
+
+ return text.join('');
+};
+
+export const codequalityPopover = state => {
+ if (state.headPath && !state.basePath) {
+ return {
+ title: s__('ciReport|Base pipeline codequality artifact not found'),
+ content: sprintf(
+ s__('ciReport|%{linkStartTag}Learn more about codequality reports %{linkEndTag}'),
+ {
+ linkStartTag: `<a href="${state.helpPath}" target="_blank" rel="noopener noreferrer">`,
+ linkEndTag: '<i class="fa fa-external-link" aria-hidden="true"></i></a>',
+ },
+ false,
+ ),
+ };
+ }
+ return {};
+};
diff --git a/app/assets/javascripts/reports/codequality_report/store/index.js b/app/assets/javascripts/reports/codequality_report/store/index.js
new file mode 100644
index 00000000000..047964260ad
--- /dev/null
+++ b/app/assets/javascripts/reports/codequality_report/store/index.js
@@ -0,0 +1,16 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import * as actions from './actions';
+import * as getters from './getters';
+import mutations from './mutations';
+import state from './state';
+
+Vue.use(Vuex);
+
+export default initialState =>
+ new Vuex.Store({
+ actions,
+ getters,
+ mutations,
+ state: state(initialState),
+ });
diff --git a/app/assets/javascripts/reports/codequality_report/store/mutation_types.js b/app/assets/javascripts/reports/codequality_report/store/mutation_types.js
new file mode 100644
index 00000000000..c362c973ae1
--- /dev/null
+++ b/app/assets/javascripts/reports/codequality_report/store/mutation_types.js
@@ -0,0 +1,5 @@
+export const SET_PATHS = 'SET_PATHS';
+
+export const REQUEST_REPORTS = 'REQUEST_REPORTS';
+export const RECEIVE_REPORTS_SUCCESS = 'RECEIVE_REPORTS_SUCCESS';
+export const RECEIVE_REPORTS_ERROR = 'RECEIVE_REPORTS_ERROR';
diff --git a/app/assets/javascripts/reports/codequality_report/store/mutations.js b/app/assets/javascripts/reports/codequality_report/store/mutations.js
new file mode 100644
index 00000000000..7ef4f3ce2db
--- /dev/null
+++ b/app/assets/javascripts/reports/codequality_report/store/mutations.js
@@ -0,0 +1,24 @@
+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.helpPath = paths.helpPath;
+ },
+ [types.REQUEST_REPORTS](state) {
+ state.isLoading = true;
+ },
+ [types.RECEIVE_REPORTS_SUCCESS](state, data) {
+ state.hasError = false;
+ state.isLoading = false;
+ state.newIssues = data.newIssues;
+ state.resolvedIssues = data.resolvedIssues;
+ },
+ [types.RECEIVE_REPORTS_ERROR](state) {
+ state.isLoading = false;
+ state.hasError = true;
+ },
+};
diff --git a/app/assets/javascripts/reports/codequality_report/store/state.js b/app/assets/javascripts/reports/codequality_report/store/state.js
new file mode 100644
index 00000000000..38ab53b432e
--- /dev/null
+++ b/app/assets/javascripts/reports/codequality_report/store/state.js
@@ -0,0 +1,15 @@
+export default () => ({
+ basePath: null,
+ headPath: null,
+
+ baseBlobPath: null,
+ headBlobPath: null,
+
+ isLoading: false,
+ hasError: false,
+
+ newIssues: [],
+ resolvedIssues: [],
+
+ helpPath: null,
+});
diff --git a/app/assets/javascripts/reports/codequality_report/store/utils/codequality_comparison.js b/app/assets/javascripts/reports/codequality_report/store/utils/codequality_comparison.js
new file mode 100644
index 00000000000..eba9e340c4e
--- /dev/null
+++ b/app/assets/javascripts/reports/codequality_report/store/utils/codequality_comparison.js
@@ -0,0 +1,41 @@
+import CodeQualityComparisonWorker from '../../workers/codequality_comparison_worker';
+
+export const parseCodeclimateMetrics = (issues = [], path = '') => {
+ return issues.map(issue => {
+ const parsedIssue = {
+ ...issue,
+ name: issue.description,
+ };
+
+ if (issue?.location?.path) {
+ let parseCodeQualityUrl = `${path}/${issue.location.path}`;
+ parsedIssue.path = issue.location.path;
+
+ if (issue?.location?.lines?.begin) {
+ parsedIssue.line = issue.location.lines.begin;
+ parseCodeQualityUrl += `#L${issue.location.lines.begin}`;
+ } else if (issue?.location?.positions?.begin?.line) {
+ parsedIssue.line = issue.location.positions.begin.line;
+ parseCodeQualityUrl += `#L${issue.location.positions.begin.line}`;
+ }
+
+ parsedIssue.urlPath = parseCodeQualityUrl;
+ }
+
+ return parsedIssue;
+ });
+};
+
+export const doCodeClimateComparison = (headIssues, baseIssues) => {
+ // Do these comparisons in worker threads to avoid blocking the main thread
+ return new Promise((resolve, reject) => {
+ const worker = new CodeQualityComparisonWorker();
+ worker.addEventListener('message', ({ data }) =>
+ data.newIssues && data.resolvedIssues ? resolve(data) : reject(data),
+ );
+ worker.postMessage({
+ headIssues,
+ baseIssues,
+ });
+ });
+};
diff --git a/app/assets/javascripts/reports/codequality_report/workers/codequality_comparison_worker.js b/app/assets/javascripts/reports/codequality_report/workers/codequality_comparison_worker.js
new file mode 100644
index 00000000000..fc55602f95c
--- /dev/null
+++ b/app/assets/javascripts/reports/codequality_report/workers/codequality_comparison_worker.js
@@ -0,0 +1,28 @@
+import { differenceBy } from 'lodash';
+
+const KEY_TO_FILTER_BY = 'fingerprint';
+
+// eslint-disable-next-line no-restricted-globals
+self.addEventListener('message', e => {
+ const { data } = e;
+
+ if (data === undefined) {
+ return null;
+ }
+
+ const { headIssues, baseIssues } = data;
+
+ if (!headIssues || !baseIssues) {
+ // eslint-disable-next-line no-restricted-globals
+ return self.postMessage({});
+ }
+
+ // eslint-disable-next-line no-restricted-globals
+ self.postMessage({
+ newIssues: differenceBy(headIssues, baseIssues, KEY_TO_FILTER_BY),
+ resolvedIssues: differenceBy(baseIssues, headIssues, KEY_TO_FILTER_BY),
+ });
+
+ // eslint-disable-next-line no-restricted-globals
+ return self.close();
+});