Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-07-06 21:08:51 +00:00
parent 691ed55a05
commit 27b73daa23
25 changed files with 196 additions and 32 deletions

View File

@ -1,9 +1,11 @@
<script>
import { GlSingleStat } from '@gitlab/ui/dist/charts';
import { __ } from '~/locale';
import { SUPPORTED_FORMATS, getFormatter } from '~/lib/utils/unit_format';
import { graphDataValidatorForValues } from '../../utils';
const defaultPrecision = 2;
const emptyStateMsg = __('No data to display');
export default {
components: {
@ -21,6 +23,9 @@ export default {
queryInfo() {
return this.graphData.metrics[0];
},
queryMetric() {
return this.queryInfo.result[0]?.metric;
},
queryResult() {
return this.queryInfo.result[0]?.value[1];
},
@ -33,6 +38,12 @@ export default {
statValue() {
let formatter;
// if field is present the metric value is not displayed. Hence
// the early exit without formatting.
if (this.graphData?.field) {
return this.queryMetric?.[this.graphData.field] ?? emptyStateMsg;
}
if (this.graphData?.maxValue) {
formatter = getFormatter(SUPPORTED_FORMATS.percent);
return formatter(this.queryResult / Number(this.graphData.maxValue), defaultPrecision);

View File

@ -173,6 +173,7 @@ const mapPanelToViewModel = ({
x_label,
y_label,
y_axis = {},
field,
metrics = [],
links = [],
max_value,
@ -193,6 +194,7 @@ const mapPanelToViewModel = ({
y_label: yAxis.name, // Changing y_label to yLabel is pending https://gitlab.com/gitlab-org/gitlab/issues/207198
yAxis,
xAxis,
field,
maxValue: max_value,
links: links.map(mapLinksToViewModel),
metrics: mapToMetricsViewModel(metrics),

View File

@ -0,0 +1,5 @@
---
title: Display metric label in single stat
merge_request: 35289
author:
type: added

View File

@ -254,6 +254,13 @@ These results can also be placed into a PostgreSQL database by setting the
`RSPEC_PROFILING_POSTGRES_URL` variable. This is used to profile the test suite
when running in the CI environment.
We store these results also when running CI jobs on the default branch on
`gitlab.com`. Statistics of these profiling data are [available
online](https://gitlab-org.gitlab.io/rspec_profiling_stats/). For example,
you can find which tests take longest to run or which execute the most
queries. This can be handy for optimizing our tests or identifying performance
issues in our code.
## Memory profiling
One of the reasons of the increased memory footprint could be Ruby memory fragmentation.

View File

@ -545,6 +545,99 @@ In order to ensure that a clean wrapper object and DOM are being used in each te
See also the [Vue Test Utils documentation on `destroy`](https://vue-test-utils.vuejs.org/api/wrapper/#destroy).
### Jest best practices
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34209) in GitLab 13.2.
#### Prefer `toBe` over `toEqual` when comparing primitive values
Jest has [`toBe`](https://jestjs.io/docs/en/expect#tobevalue) and
[`toEqual`](https://jestjs.io/docs/en/expect#toequalvalue) matchers.
As [`toBe`](https://jestjs.io/docs/en/expect#tobevalue) uses
[`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)
to compare values, it's faster (by default) than using `toEqual`.
While the latter will eventually fallback to leverage [`Object.is`](https://github.com/facebook/jest/blob/master/packages/expect/src/jasmineUtils.ts#L91),
for primitive values, it should only be used when complex objects need a comparison.
Examples:
```javascript
const foo = 1;
// good
expect(foo).toBe(1);
// bad
expect(foo).toEqual(1);
```
#### Prefer more befitting matchers
Jest provides useful matchers like `toHaveLength` or `toBeUndefined` to make your tests more
readable and to produce more understandable error messages. Check their docs for the
[full list of matchers](https://jestjs.io/docs/en/expect#methods).
Examples:
```javascript
const arr = [1, 2];
// prints:
// Expected length: 1
// Received length: 2
expect(arr).toHaveLength(1);
// prints:
// Expected: 1
// Received: 2
expect(arr.length).toBe(1);
// prints:
// expect(received).toBe(expected) // Object.is equality
// Expected: undefined
// Received: "bar"
const foo = 'bar';
expect(foo).toBe(undefined);
// prints:
// expect(received).toBeUndefined()
// Received: "bar"
const foo = 'bar';
expect(foo).toBeUndefined();
```
#### Avoid using `toBeTruthy` or `toBeFalsy`
Jest also provides following matchers: `toBeTruthy` and `toBeFalsy`. We should not use them because
they make tests weaker and produce false-positive results.
For example, `expect(someBoolean).toBeFalsy()` passes when `someBoolean === null`, and when
`someBoolean === false`.
#### Tricky `toBeDefined` matcher
Jest has the tricky `toBeDefined` matcher that can produce false positive test. Because it
[validates](https://github.com/facebook/jest/blob/master/packages/expect/src/matchers.ts#L204)
the given value for `undefined` only.
```javascript
// good
expect(wrapper.find('foo').exists()).toBe(true);
// bad
// if finder returns null, the test will pass
expect(wrapper.find('foo')).toBeDefined();
```
#### Avoid using `setImmediate`
Try to avoid using `setImmediate`. `setImmediate` is an ad-hoc solution to run your callback after
the I/O completes. And it's not part of the Web API, hence, we target NodeJS environments in our
unit tests.
Instead of `setImmediate`, use `jest.runAllTimers` or `jest.runOnlyPendingTimers` to run pending timers.
The latter is useful when you have `setInterval` in the code. **Remember:** our Jest configuration uses fake timers.
## Factories
TBU

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -74,7 +74,7 @@ You can also dismiss vulnerabilities in the table:
1. Select the checkbox for each vulnerability you want to dismiss.
1. In the menu that appears, select the reason for dismissal and click **Dismiss Selected**.
![Project Security Dashboard](img/project_security_dashboard_v13_2_noNav.png)
![Project Security Dashboard](img/project_security_dashboard_v13_2.png)
## Group Security Dashboard

View File

@ -139,13 +139,13 @@ module Gitlab
%r{\Arubocop/cop/migration(/|\.rb)} => :database,
%r{\A(\.gitlab-ci\.yml\z|\.gitlab\/ci)} => :engineering_productivity,
%r{\A\.codeclimate\.yml\z} => :engineering_productivity,
%r{\A\.overcommit\.yml\.example\z} => :engineering_productivity,
%r{\Atooling/overcommit/} => :engineering_productivity,
%r{\A.editorconfig\z} => :engineering_productivity,
%r{\A\.editorconfig\z} => :engineering_productivity,
%r{Dangerfile\z} => :engineering_productivity,
%r{\A(ee/)?(danger/|lib/gitlab/danger/)} => :engineering_productivity,
%r{\A(ee/)?scripts/} => :engineering_productivity,
%r{\A\.codeclimate\.yml\z} => :engineering_productivity,
%r{\Atooling/} => :engineering_productivity,
%r{\A(ee/)?app/(?!assets|views)[^/]+} => :backend,
%r{\A(ee/)?(bin|config|generator_templates|lib|rubocop)/} => :backend,

View File

@ -752,6 +752,9 @@ msgstr ""
msgid "(external source)"
msgstr ""
msgid "(line: %{startLine})"
msgstr ""
msgid "(removed)"
msgstr ""
@ -25677,6 +25680,9 @@ msgstr ""
msgid "Vulnerability|File"
msgstr ""
msgid "Vulnerability|Identifier"
msgstr ""
msgid "Vulnerability|Identifiers"
msgstr ""

View File

@ -40,7 +40,7 @@
"@babel/plugin-syntax-import-meta": "^7.10.1",
"@babel/preset-env": "^7.10.1",
"@gitlab/at.js": "1.5.5",
"@gitlab/svgs": "1.148.0",
"@gitlab/svgs": "1.150.0",
"@gitlab/ui": "17.16.0",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3-1",

View File

@ -13,6 +13,10 @@ module QA
@secondary_node = @second_node
end
def enable_writes
shell "docker exec praefect bash -c '/opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml enable-writes -virtual-storage default'"
end
def stop_primary_node
shell "docker stop #{@primary_node}"
@secondary_node, @primary_node = @primary_node, @secondary_node

View File

@ -10,7 +10,7 @@ module QA
end
end
let(:initial_file) { 'pushed_to_primary.txt' }
let(:final_file) { 'pushed_to_secondary.txt' }
let(:final_file) { 'committed_to_primary.txt' }
let(:praefect_manager) { Service::PraefectManager.new }
before do
@ -41,11 +41,13 @@ module QA
expect(show).to have_file(initial_file)
end
praefect_manager.enable_writes
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.project = project
commit.add_files([
{
file_path: 'committed_to_primary.txt',
file_path: final_file,
content: 'This should exist on both nodes too'
}
])

View File

@ -3,7 +3,7 @@
require 'pathname'
module QA
context 'Configure' do
RSpec.describe 'Configure' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = Runtime::Env.auto_devops_project_name || 'autodevops-project'

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
context 'Configure' do
RSpec.describe 'Configure' do
describe 'Kubernetes Cluster Integration', :orchestrated, :kubernetes, :requires_admin, :skip_live_env do
context 'Project Clusters' do
let!(:cluster) { Service::KubernetesCluster.new(provider_class: Service::ClusterProvider::K3s).create! }

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'gitlab'
require_relative File.expand_path('../../lib/quality/helm3_client.rb', __dir__)
require_relative File.expand_path('../../lib/quality/kubernetes_client.rb', __dir__)
require_relative File.expand_path('../../tooling/lib/tooling/helm3_client.rb', __dir__)
require_relative File.expand_path('../../tooling/lib/tooling/kubernetes_client.rb', __dir__)
class AutomatedCleanup
attr_reader :project_path, :gitlab_token
@ -44,11 +44,11 @@ class AutomatedCleanup
end
def helm
@helm ||= Quality::Helm3Client.new(namespace: review_apps_namespace)
@helm ||= Tooling::Helm3Client.new(namespace: review_apps_namespace)
end
def kubernetes
@kubernetes ||= Quality::KubernetesClient.new(namespace: review_apps_namespace)
@kubernetes ||= Tooling::KubernetesClient.new(namespace: review_apps_namespace)
end
def perform_gitlab_environment_cleanup!(days_for_stop:, days_for_delete:)
@ -76,7 +76,7 @@ class AutomatedCleanup
if deployed_at < delete_threshold
deleted_environment = delete_environment(environment, deployment)
if deleted_environment
release = Quality::Helm3Client::Release.new(environment.slug, 1, deployed_at.to_s, nil, nil, review_apps_namespace)
release = Tooling::Helm3Client::Release.new(environment.slug, 1, deployed_at.to_s, nil, nil, review_apps_namespace)
releases_to_delete << release
end
else
@ -157,11 +157,11 @@ class AutomatedCleanup
helm.delete(release_name: releases_names)
kubernetes.cleanup(release_name: releases_names, wait: false)
rescue Quality::Helm3Client::CommandFailedError => ex
rescue Tooling::Helm3Client::CommandFailedError => ex
raise ex unless ignore_exception?(ex.message, IGNORED_HELM_ERRORS)
puts "Ignoring the following Helm error:\n#{ex}\n"
rescue Quality::KubernetesClient::CommandFailedError => ex
rescue Tooling::KubernetesClient::CommandFailedError => ex
raise ex unless ignore_exception?(ex.message, IGNORED_KUBERNETES_ERRORS)
puts "Ignoring the following Kubernetes error:\n#{ex}\n"

View File

@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import SingleStatChart from '~/monitoring/components/charts/single_stat.vue';
import { singleStatMetricsResult } from '../../mock_data';
import { singleStatMetricsResult, singleStatMetricsWithFieldResult } from '../../mock_data';
describe('Single Stat Chart component', () => {
let singleStatChart;
@ -66,6 +66,31 @@ describe('Single Stat Chart component', () => {
expect(singleStatChart.vm.statValue).toContain('NaN');
});
describe('field attribute', () => {
it('displays a label value instead of metric value when field attribute is used', () => {
singleStatChart.setProps({
graphData: singleStatMetricsWithFieldResult,
});
return singleStatChart.vm.$nextTick(() => {
expect(singleStatChart.vm.statValue).toContain('prometheus');
});
});
it('displays No data to display if field attribute is not present', () => {
singleStatChart.setProps({
graphData: {
...singleStatMetricsWithFieldResult,
field: 'this-does-not-exist',
},
});
return singleStatChart.vm.$nextTick(() => {
expect(singleStatChart.vm.statValue).toContain('No data to display');
});
});
});
});
});
});

View File

@ -359,6 +359,11 @@ export const singleStatMetricsResult = {
],
};
export const singleStatMetricsWithFieldResult = {
...singleStatMetricsResult,
field: 'job',
};
export const graphDataPrometheusQueryRangeMultiTrack = {
title: 'Super Chart A3',
type: 'heatmap',

View File

@ -10,6 +10,7 @@ describe('MRWidgetSuggestPipeline', () => {
let trackingSpy;
const mockTrackingOnWrapper = () => {
unmockTracking();
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
};

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require_relative '../../../../tooling/lib/tooling/helm3_client'
RSpec.describe Quality::Helm3Client do
RSpec.describe Tooling::Helm3Client do
let(:namespace) { 'review-apps' }
let(:release_name) { 'my-release' }
let(:raw_helm_list_page1) do

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require_relative '../../../../tooling/lib/tooling/kubernetes_client'
RSpec.describe Quality::KubernetesClient do
RSpec.describe Tooling::KubernetesClient do
let(:namespace) { 'review-apps' }
let(:release_name) { 'my-release' }
let(:pod_for_release) { "pod-my-release-abcd" }

View File

@ -3,7 +3,7 @@
require_relative '../../../../tooling/lib/tooling/test_file_finder'
RSpec.describe Tooling::TestFileFinder do
subject { Tooling::TestFileFinder.new(file) }
subject { described_class.new(file) }
describe '#test_files' do
context 'when given non .rb files' do

View File

@ -1,9 +1,11 @@
# frozen_string_literal: true
require 'time'
require_relative '../gitlab/popen' unless defined?(Gitlab::Popen)
require 'json'
require_relative '../../../lib/gitlab/popen' unless defined?(Gitlab::Popen)
require_relative '../../../lib/gitlab/json' unless defined?(Gitlab::Json)
module Quality
module Tooling
class Helm3Client
CommandFailedError = Class.new(StandardError)
@ -65,12 +67,12 @@ module Quality
%(--output json),
*args
]
releases = JSON.parse(run_command(command))
releases = Gitlab::Json.parse(run_command(command))
releases.map do |release|
Release.new(*release.values_at(*RELEASE_JSON_ATTRIBUTES))
end
rescue JSON::ParserError => ex
rescue ::JSON::ParserError => ex
puts "Ignoring this JSON parsing error: #{ex}" # rubocop:disable Rails/Output
[]
end

View File

@ -1,8 +1,9 @@
# frozen_string_literal: true
require_relative '../gitlab/popen' unless defined?(Gitlab::Popen)
require_relative '../../../lib/gitlab/popen' unless defined?(Gitlab::Popen)
require_relative '../../../lib/gitlab/json' unless defined?(Gitlab::JSON)
module Quality
module Tooling
class KubernetesClient
RESOURCE_LIST = 'ingress,svc,pdb,hpa,deploy,statefulset,job,pod,secret,configmap,pvc,secret,clusterrole,clusterrolebinding,role,rolebinding,sa,crd'
CommandFailedError = Class.new(StandardError)

View File

@ -843,10 +843,10 @@
eslint-plugin-vue "^6.2.1"
vue-eslint-parser "^7.0.0"
"@gitlab/svgs@1.148.0":
version "1.148.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.148.0.tgz#cb3fd68249d7e97d0c578bf443459a32370a6dba"
integrity sha512-5GJtUNjCBzEdfi1J3jZPr7UUsvZ1KYnzK3VkMPmp+t2GNWHtdqBmi3Y6WKTOWJo8qFIAJO0tIs6w7XMMCIUBCg==
"@gitlab/svgs@1.150.0":
version "1.150.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.150.0.tgz#7dbbdf1b50c4409adf30d23710bbe4515608e245"
integrity sha512-jfD1EiawNlBM1XNEz7hriPJg2UOX6zE2/lKMIocSpkg9R58VGyIr+oyWOTn2AfknrepsLfnTiGJNveLdRYcy4w==
"@gitlab/ui@17.16.0":
version "17.16.0"