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-11-19 11:27:35 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-11-19 11:27:35 +0300
commit7e9c479f7de77702622631cff2628a9c8dcbc627 (patch)
treec8f718a08e110ad7e1894510980d2155a6549197 /app/assets/javascripts/reports
parente852b0ae16db4052c1c567d9efa4facc81146e88 (diff)
Add latest changes from gitlab-org/gitlab@13-6-stable-eev13.6.0-rc42
Diffstat (limited to 'app/assets/javascripts/reports')
-rw-r--r--app/assets/javascripts/reports/codequality_report/components/codequality_issue_body.vue44
-rw-r--r--app/assets/javascripts/reports/codequality_report/constants.js17
-rw-r--r--app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue1
-rw-r--r--app/assets/javascripts/reports/codequality_report/store/getters.js3
-rw-r--r--app/assets/javascripts/reports/components/grouped_test_reports_app.vue45
-rw-r--r--app/assets/javascripts/reports/components/report_section.vue5
-rw-r--r--app/assets/javascripts/reports/components/test_issue_body.vue24
-rw-r--r--app/assets/javascripts/reports/store/mutations.js8
-rw-r--r--app/assets/javascripts/reports/store/utils.js42
9 files changed, 170 insertions, 19 deletions
diff --git a/app/assets/javascripts/reports/codequality_report/components/codequality_issue_body.vue b/app/assets/javascripts/reports/codequality_report/components/codequality_issue_body.vue
index 0c758ee2b5c..d0a5615bb57 100644
--- a/app/assets/javascripts/reports/codequality_report/components/codequality_issue_body.vue
+++ b/app/assets/javascripts/reports/codequality_report/components/codequality_issue_body.vue
@@ -3,15 +3,21 @@
* Renders Code quality body text
* Fixed: [name] in [link]:[line]
*/
+import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
import ReportLink from '~/reports/components/report_link.vue';
import { STATUS_SUCCESS } from '~/reports/constants';
+import { s__ } from '~/locale';
+import { SEVERITY_CLASSES, SEVERITY_ICONS } from '../constants';
export default {
name: 'CodequalityIssueBody',
-
components: {
+ GlIcon,
ReportLink,
},
+ directives: {
+ tooltip: GlTooltipDirective,
+ },
props: {
status: {
type: String,
@@ -23,20 +29,44 @@ export default {
},
},
computed: {
+ issueName() {
+ return `${this.severityLabel} - ${this.issue.name}`;
+ },
isStatusSuccess() {
return this.status === STATUS_SUCCESS;
},
+ severityClass() {
+ return SEVERITY_CLASSES[this.issue.severity] || SEVERITY_CLASSES.unknown;
+ },
+ severityIcon() {
+ return SEVERITY_ICONS[this.issue.severity] || SEVERITY_ICONS.unknown;
+ },
+ severityLabel() {
+ return this.$options.severityText[this.issue.severity] || this.$options.severityText.unknown;
+ },
+ },
+ severityText: {
+ info: s__('severity|Info'),
+ minor: s__('severity|Minor'),
+ major: s__('severity|Major'),
+ critical: s__('severity|Critical'),
+ blocker: s__('severity|Blocker'),
+ unknown: s__('severity|Unknown'),
},
};
</script>
<template>
- <div class="report-block-list-issue-description gl-mt-2 gl-mb-2">
- <div class="report-block-list-issue-description-text">
- <template v-if="isStatusSuccess">{{ s__('ciReport|Fixed:') }}</template>
+ <div class="gl-display-flex gl-mt-2 gl-mb-2 gl-w-full">
+ <span :class="severityClass" class="gl-mr-5" data-testid="codequality-severity-icon">
+ <gl-icon v-tooltip="severityLabel" :name="severityIcon" :size="12" />
+ </span>
+ <div class="gl-flex-fill-1">
+ <div>
+ <strong v-if="isStatusSuccess">{{ s__('ciReport|Fixed:') }}</strong>
+ {{ issueName }}
+ </div>
- {{ issue.name }}
+ <report-link v-if="issue.path" :issue="issue" />
</div>
-
- <report-link v-if="issue.path" :issue="issue" />
</div>
</template>
diff --git a/app/assets/javascripts/reports/codequality_report/constants.js b/app/assets/javascripts/reports/codequality_report/constants.js
new file mode 100644
index 00000000000..502977e714c
--- /dev/null
+++ b/app/assets/javascripts/reports/codequality_report/constants.js
@@ -0,0 +1,17 @@
+export const SEVERITY_CLASSES = {
+ info: 'text-primary-400',
+ minor: 'text-warning-200',
+ major: 'text-warning-400',
+ critical: 'text-danger-600',
+ blocker: 'text-danger-800',
+ unknown: 'text-secondary-400',
+};
+
+export const SEVERITY_ICONS = {
+ info: 'severity-info',
+ minor: 'severity-low',
+ major: 'severity-medium',
+ critical: 'severity-high',
+ blocker: 'severity-critical',
+ unknown: 'severity-unknown',
+};
diff --git a/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue b/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue
index f3d5b1a80f8..5c8f31d7da0 100644
--- a/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue
+++ b/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue
@@ -78,6 +78,7 @@ export default {
:has-issues="hasCodequalityIssues"
:component="$options.componentNames.CodequalityIssueBody"
:popover-options="codequalityPopover"
+ :show-report-section-status-icon="false"
class="js-codequality-widget mr-widget-border-top mr-report"
/>
</template>
diff --git a/app/assets/javascripts/reports/codequality_report/store/getters.js b/app/assets/javascripts/reports/codequality_report/store/getters.js
index 5df58c7f85f..d7c31bcf459 100644
--- a/app/assets/javascripts/reports/codequality_report/store/getters.js
+++ b/app/assets/javascripts/reports/codequality_report/store/getters.js
@@ -1,5 +1,6 @@
import { LOADING, ERROR, SUCCESS } from '../../constants';
import { sprintf, __, s__, n__ } from '~/locale';
+import { spriteIcon } from '~/lib/utils/common_utils';
export const hasCodequalityIssues = state =>
Boolean(state.newIssues?.length || state.resolvedIssues?.length);
@@ -48,7 +49,7 @@ export const codequalityPopover = state => {
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>',
+ linkEndTag: `${spriteIcon('external-link', 's16')}</a>`,
},
false,
),
diff --git a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
index 47f04019595..c13df60198b 100644
--- a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
+++ b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue
@@ -1,5 +1,6 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
+import { once } from 'lodash';
import { GlButton } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale';
import { componentNames } from './issue_body';
@@ -8,8 +9,14 @@ import SummaryRow from './summary_row.vue';
import IssuesList from './issues_list.vue';
import Modal from './modal.vue';
import createStore from '../store';
+import Tracking from '~/tracking';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { summaryTextBuilder, reportTextBuilder, statusIcon } from '../store/utils';
+import {
+ summaryTextBuilder,
+ reportTextBuilder,
+ statusIcon,
+ recentFailuresTextBuilder,
+} from '../store/utils';
export default {
name: 'GroupedTestReportsApp',
@@ -21,7 +28,7 @@ export default {
Modal,
GlButton,
},
- mixins: [glFeatureFlagsMixin()],
+ mixins: [glFeatureFlagsMixin(), Tracking.mixin()],
props: {
endpoint: {
type: String,
@@ -58,6 +65,11 @@ export default {
showViewFullReport() {
return this.pipelinePath.length;
},
+ handleToggleEvent() {
+ return once(() => {
+ this.track(this.$options.expandEvent);
+ });
+ },
},
created() {
this.setEndpoint(this.endpoint);
@@ -79,6 +91,12 @@ export default {
return reportTextBuilder(name, summary);
},
+ hasRecentFailures(summary) {
+ return this.glFeatures.testFailureHistory && summary?.recentlyFailed > 0;
+ },
+ recentFailuresText(summary) {
+ return recentFailuresTextBuilder(summary);
+ },
getReportIcon(report) {
return statusIcon(report.status);
},
@@ -102,6 +120,7 @@ export default {
return report.resolved_failures.concat(report.resolved_errors);
},
},
+ expandEvent: 'expand_test_report_widget',
};
</script>
<template>
@@ -111,9 +130,11 @@ export default {
:loading-text="groupedSummaryText"
:error-text="groupedSummaryText"
:has-issues="reports.length > 0"
+ :should-emit-toggle-event="true"
class="mr-widget-section grouped-security-reports mr-report"
+ @toggleEvent="handleToggleEvent"
>
- <template v-if="showViewFullReport" #actionButtons>
+ <template v-if="showViewFullReport" #action-buttons>
<gl-button
:href="testTabURL"
target="_blank"
@@ -124,14 +145,22 @@ export default {
{{ s__('ciReport|View full report') }}
</gl-button>
</template>
+ <template v-if="hasRecentFailures(summary)" #sub-heading>
+ {{ recentFailuresText(summary) }}
+ </template>
<template #body>
<div class="mr-widget-grouped-section report-block">
<template v-for="(report, i) in reports">
- <summary-row
- :key="`summary-row-${i}`"
- :summary="reportText(report)"
- :status-icon="getReportIcon(report)"
- />
+ <summary-row :key="`summary-row-${i}`" :status-icon="getReportIcon(report)">
+ <template #summary>
+ <div class="gl-display-inline-flex gl-flex-direction-column">
+ <div>{{ reportText(report) }}</div>
+ <div v-if="hasRecentFailures(report.summary)">
+ {{ recentFailuresText(report.summary) }}
+ </div>
+ </div>
+ </template>
+ </summary-row>
<issues-list
v-if="shouldRenderIssuesList(report)"
:key="`issues-list-${i}`"
diff --git a/app/assets/javascripts/reports/components/report_section.vue b/app/assets/javascripts/reports/components/report_section.vue
index 63af8a5a9ac..f245e2bfd2f 100644
--- a/app/assets/javascripts/reports/components/report_section.vue
+++ b/app/assets/javascripts/reports/components/report_section.vue
@@ -181,14 +181,15 @@ export default {
<slot :name="slotName"></slot>
<popover v-if="hasPopover" :options="popoverOptions" class="gl-ml-2" />
</div>
- <slot name="subHeading"></slot>
+ <slot name="sub-heading"></slot>
</div>
- <slot name="actionButtons"></slot>
+ <slot name="action-buttons"></slot>
<button
v-if="isCollapsible"
type="button"
+ data-testid="report-section-expand-button"
class="js-collapse-btn btn float-right btn-sm align-self-center qa-expand-report-button"
@click="toggleCollapsed"
>
diff --git a/app/assets/javascripts/reports/components/test_issue_body.vue b/app/assets/javascripts/reports/components/test_issue_body.vue
index 4e0631740d8..5e9a5b03543 100644
--- a/app/assets/javascripts/reports/components/test_issue_body.vue
+++ b/app/assets/javascripts/reports/components/test_issue_body.vue
@@ -1,8 +1,15 @@
<script>
import { mapActions } from 'vuex';
+import { GlBadge } from '@gitlab/ui';
+import { n__ } from '~/locale';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
export default {
name: 'TestIssueBody',
+ components: {
+ GlBadge,
+ },
+ mixins: [glFeatureFlagsMixin()],
props: {
issue: {
type: Object,
@@ -19,8 +26,20 @@ export default {
default: false,
},
},
+ computed: {
+ showRecentFailures() {
+ return this.glFeatures.testFailureHistory && this.issue.recent_failures;
+ },
+ },
methods: {
...mapActions(['openModal']),
+ recentFailuresText(count) {
+ return n__(
+ 'Failed %d time in the last 14 days',
+ 'Failed %d times in the last 14 days',
+ count,
+ );
+ },
},
};
</script>
@@ -32,7 +51,10 @@ export default {
class="btn-link btn-blank text-left break-link vulnerability-name-button"
@click="openModal({ issue })"
>
- <div v-if="isNew" class="badge badge-danger gl-mr-2">{{ s__('New') }}</div>
+ <gl-badge v-if="isNew" variant="danger" class="gl-mr-2">{{ s__('New') }}</gl-badge>
+ <gl-badge v-if="showRecentFailures" variant="warning" class="gl-mr-2">
+ {{ recentFailuresText(issue.recent_failures) }}
+ </gl-badge>
{{ issue.name }}
</button>
</div>
diff --git a/app/assets/javascripts/reports/store/mutations.js b/app/assets/javascripts/reports/store/mutations.js
index 35ab72bf694..acaa98754b0 100644
--- a/app/assets/javascripts/reports/store/mutations.js
+++ b/app/assets/javascripts/reports/store/mutations.js
@@ -1,4 +1,5 @@
import * as types from './mutation_types';
+import { countRecentlyFailedTests } from './utils';
export default {
[types.SET_ENDPOINT](state, endpoint) {
@@ -16,9 +17,15 @@ export default {
state.summary.resolved = response.summary.resolved;
state.summary.failed = response.summary.failed;
state.summary.errored = response.summary.errored;
+ state.summary.recentlyFailed = countRecentlyFailedTests(response.suites);
state.status = response.status;
state.reports = response.suites;
+
+ state.reports.forEach((report, i) => {
+ if (!state.reports[i].summary) return;
+ state.reports[i].summary.recentlyFailed = countRecentlyFailedTests(report);
+ });
},
[types.RECEIVE_REPORTS_ERROR](state) {
state.isLoading = false;
@@ -30,6 +37,7 @@ export default {
resolved: 0,
failed: 0,
errored: 0,
+ recentlyFailed: 0,
};
state.status = null;
},
diff --git a/app/assets/javascripts/reports/store/utils.js b/app/assets/javascripts/reports/store/utils.js
index 5d3d9ddda3b..fd6f4933cfa 100644
--- a/app/assets/javascripts/reports/store/utils.js
+++ b/app/assets/javascripts/reports/store/utils.js
@@ -48,6 +48,48 @@ export const reportTextBuilder = (name = '', results = {}) => {
return sprintf(__('%{name} found %{resultsString}'), { name, resultsString });
};
+export const recentFailuresTextBuilder = (summary = {}) => {
+ const { failed, recentlyFailed } = summary;
+ if (!failed || !recentlyFailed) return '';
+
+ if (failed < 2) {
+ return sprintf(
+ s__(
+ 'Reports|%{recentlyFailed} out of %{failed} failed test has failed more than once in the last 14 days',
+ ),
+ { recentlyFailed, failed },
+ );
+ }
+ return sprintf(
+ n__(
+ s__(
+ 'Reports|%{recentlyFailed} out of %{failed} failed tests has failed more than once in the last 14 days',
+ ),
+ s__(
+ 'Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days',
+ ),
+ recentlyFailed,
+ ),
+ { recentlyFailed, failed },
+ );
+};
+
+export const countRecentlyFailedTests = subject => {
+ // handle either a single report or an array of reports
+ const reports = !subject.length ? [subject] : subject;
+
+ return reports
+ .map(report => {
+ return (
+ [report.new_failures, report.existing_failures, report.resolved_failures]
+ // only count tests which have failed more than once
+ .map(failureArray => failureArray.filter(failure => failure.recent_failures > 1).length)
+ .reduce((total, count) => total + count, 0)
+ );
+ })
+ .reduce((total, count) => total + count, 0);
+};
+
export const statusIcon = status => {
if (status === STATUS_FAILED) {
return ICON_WARNING;