Commit cf352eca authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 2e139997f05d
......@@ -455,9 +455,9 @@ gem 'google-protobuf', '~> 3.8.0'
gem 'toml-rb', '~> 1.0.0', require: false
# Feature toggles
gem 'flipper', '~> 0.13.0'
gem 'flipper-active_record', '~> 0.13.0'
gem 'flipper-active_support_cache_store', '~> 0.13.0'
gem 'flipper', '~> 0.17.1'
gem 'flipper-active_record', '~> 0.17.1'
gem 'flipper-active_support_cache_store', '~> 0.17.1'
gem 'unleash', '~> 0.1.5'
# Structured logging
......
......@@ -285,13 +285,13 @@ GEM
fast_gettext (1.6.0)
ffaker (2.10.0)
ffi (1.11.1)
flipper (0.13.0)
flipper-active_record (0.13.0)
activerecord (>= 3.2, < 6)
flipper (~> 0.13.0)
flipper-active_support_cache_store (0.13.0)
activesupport (>= 3.2, < 6)
flipper (~> 0.13.0)
flipper (0.17.1)
flipper-active_record (0.17.1)
activerecord (>= 4.2, < 7)
flipper (~> 0.17.1)
flipper-active_support_cache_store (0.17.1)
activesupport (>= 4.2, < 7)
flipper (~> 0.17.1)
flowdock (0.7.1)
httparty (~> 0.7)
multi_json
......@@ -1149,9 +1149,9 @@ DEPENDENCIES
faraday_middleware-aws-signers-v4
fast_blank
ffaker (~> 2.10)
flipper (~> 0.13.0)
flipper-active_record (~> 0.13.0)
flipper-active_support_cache_store (~> 0.13.0)
flipper (~> 0.17.1)
flipper-active_record (~> 0.17.1)
flipper-active_support_cache_store (~> 0.17.1)
flowdock (~> 0.7)
fog-aliyun (~> 0.3)
fog-aws (~> 3.5)
......
......@@ -76,6 +76,10 @@ class Project < ApplicationRecord
delegate :no_import?, to: :import_state, allow_nil: true
# TODO: remove once GitLab 12.5 is released
# https://gitlab.com/gitlab-org/gitlab/issues/34638
self.ignored_columns += %i[merge_requests_require_code_owner_approval]
default_value_for :archived, false
default_value_for :resolve_outdated_diff_discussions, false
default_value_for :container_registry_enabled, gitlab_config_features.container_registry
......
---
title: Ignore deprecated column and remove references to it
merge_request: 18911
author:
type: deprecated
---
title: Apply correctly the limit of 10 designs per upload
merge_request:
author:
type: fixed
......@@ -47,6 +47,13 @@ A database **reviewer**'s role is to:
reassign MR to the database **maintainer** suggested by Reviewer
Roulette.
#### When there are no database maintainers available
Currently we have a [critical shortage of database maintainers](https://gitlab.com/gitlab-org/gitlab/issues/29717). Until we are able to increase the number of database maintainers to support the volume of reviews, we have implemented this temporary solution. If the database **reviewer** cannot find an available database **maintainer** then:
1. Assign the MR for a second review by a **database trainee maintainer** for further review.
1. Once satisfied with the review process, and if the database **maintainer** is still not available, skip the database maintainer approval step and assign the merge request to a backend maintainer for final review and approval.
A database **maintainer**'s role is to:
- Perform the final database review on the MR.
......
import Vue from 'vue';
import paginationComp from '~/vue_shared/components/pagination/table_pagination.vue';
import { shallowMount } from '@vue/test-utils';
import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
describe('Pagination component', () => {
let component;
let PaginationComponent;
let wrapper;
let spy;
let mountComponent;
const mountComponent = props => {
wrapper = shallowMount(TablePagination, {
sync: false,
propsData: props,
});
};
const findFirstButtonLink = () => wrapper.find('.js-first-button .page-link');
const findPreviousButton = () => wrapper.find('.js-previous-button');
const findPreviousButtonLink = () => wrapper.find('.js-previous-button .page-link');
const findNextButton = () => wrapper.find('.js-next-button');
const findNextButtonLink = () => wrapper.find('.js-next-button .page-link');
const findLastButtonLink = () => wrapper.find('.js-last-button .page-link');
const findPages = () => wrapper.findAll('.page');
const findSeparator = () => wrapper.find('.separator');
beforeEach(() => {
spy = jasmine.createSpy('spy');
PaginationComponent = Vue.extend(paginationComp);
spy = jest.fn();
});
mountComponent = function(props) {
return new PaginationComponent({
propsData: props,
}).$mount();
};
afterEach(() => {
wrapper.destroy();
});
describe('render', () => {
it('should not render anything', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: NaN,
page: 1,
......@@ -32,12 +43,12 @@ describe('Pagination component', () => {
change: spy,
});
expect(component.$el.childNodes.length).toEqual(0);
expect(wrapper.isEmpty()).toBe(true);
});
describe('prev button', () => {
it('should be disabled and non clickable', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 2,
page: 1,
......@@ -49,17 +60,13 @@ describe('Pagination component', () => {
change: spy,
});
expect(
component.$el.querySelector('.js-previous-button').classList.contains('disabled'),
).toEqual(true);
component.$el.querySelector('.js-previous-button .page-link').click();
expect(findPreviousButton().classes()).toContain('disabled');
findPreviousButtonLink().trigger('click');
expect(spy).not.toHaveBeenCalled();
});
it('should be disabled and non clickable when total and totalPages are NaN', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 2,
page: 1,
......@@ -70,18 +77,13 @@ describe('Pagination component', () => {
},
change: spy,
});
expect(
component.$el.querySelector('.js-previous-button').classList.contains('disabled'),
).toEqual(true);
component.$el.querySelector('.js-previous-button .page-link').click();
expect(findPreviousButton().classes()).toContain('disabled');
findPreviousButtonLink().trigger('click');
expect(spy).not.toHaveBeenCalled();
});
it('should be enabled and clickable', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 3,
page: 2,
......@@ -92,14 +94,12 @@ describe('Pagination component', () => {
},
change: spy,
});
component.$el.querySelector('.js-previous-button .page-link').click();
findPreviousButtonLink().trigger('click');
expect(spy).toHaveBeenCalledWith(1);
});
it('should be enabled and clickable when total and totalPages are NaN', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 3,
page: 2,
......@@ -110,16 +110,14 @@ describe('Pagination component', () => {
},
change: spy,
});
component.$el.querySelector('.js-previous-button .page-link').click();
findPreviousButtonLink().trigger('click');
expect(spy).toHaveBeenCalledWith(1);
});
});
describe('first button', () => {
it('should call the change callback with the first page', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 3,
page: 2,
......@@ -130,18 +128,14 @@ describe('Pagination component', () => {
},
change: spy,
});
const button = component.$el.querySelector('.js-first-button .page-link');
expect(button.textContent.trim()).toEqual('« First');
button.click();
const button = findFirstButtonLink();
expect(button.text().trim()).toEqual('« First');
button.trigger('click');
expect(spy).toHaveBeenCalledWith(1);
});
it('should call the change callback with the first page when total and totalPages are NaN', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 3,
page: 2,
......@@ -152,20 +146,16 @@ describe('Pagination component', () => {
},
change: spy,
});
const button = component.$el.querySelector('.js-first-button .page-link');
expect(button.textContent.trim()).toEqual('« First');
button.click();
const button = findFirstButtonLink();
expect(button.text().trim()).toEqual('« First');
button.trigger('click');
expect(spy).toHaveBeenCalledWith(1);
});
});
describe('last button', () => {
it('should call the change callback with the last page', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 3,
page: 2,
......@@ -176,18 +166,14 @@ describe('Pagination component', () => {
},
change: spy,
});
const button = component.$el.querySelector('.js-last-button .page-link');
expect(button.textContent.trim()).toEqual('Last »');
button.click();
const button = findLastButtonLink();
expect(button.text().trim()).toEqual('Last »');
button.trigger('click');
expect(spy).toHaveBeenCalledWith(5);
});
it('should not render', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 3,
page: 2,
......@@ -198,14 +184,13 @@ describe('Pagination component', () => {
},
change: spy,
});
expect(component.$el.querySelector('.js-last-button .page-link')).toBeNull();
expect(findLastButtonLink().exists()).toBe(false);
});
});
describe('next button', () => {
it('should be disabled and non clickable', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: NaN,
page: 5,
......@@ -216,16 +201,17 @@ describe('Pagination component', () => {
},
change: spy,
});
expect(component.$el.querySelector('.js-next-button').textContent.trim()).toEqual('Next ›');
component.$el.querySelector('.js-next-button .page-link').click();
expect(
findNextButton()
.text()
.trim(),
).toEqual('Next ›');
findNextButtonLink().trigger('click');
expect(spy).not.toHaveBeenCalled();
});
it('should be disabled and non clickable when total and totalPages are NaN', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: NaN,
page: 5,
......@@ -236,16 +222,17 @@ describe('Pagination component', () => {
},
change: spy,
});
expect(component.$el.querySelector('.js-next-button').textContent.trim()).toEqual('Next ›');
component.$el.querySelector('.js-next-button .page-link').click();
expect(
findNextButton()
.text()
.trim(),
).toEqual('Next ›');
findNextButtonLink().trigger('click');
expect(spy).not.toHaveBeenCalled();
});
it('should be enabled and clickable', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 4,
page: 3,
......@@ -256,14 +243,12 @@ describe('Pagination component', () => {
},
change: spy,
});
component.$el.querySelector('.js-next-button .page-link').click();
findNextButtonLink().trigger('click');
expect(spy).toHaveBeenCalledWith(4);
});
it('should be enabled and clickable when total and totalPages are NaN', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 4,
page: 3,
......@@ -274,16 +259,14 @@ describe('Pagination component', () => {
},
change: spy,
});
component.$el.querySelector('.js-next-button .page-link').click();
findNextButtonLink().trigger('click');
expect(spy).toHaveBeenCalledWith(4);
});
});
describe('numbered buttons', () => {
it('should render 5 pages', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 4,
page: 3,
......@@ -294,12 +277,11 @@ describe('Pagination component', () => {
},
change: spy,
});
expect(component.$el.querySelectorAll('.page').length).toEqual(5);
expect(findPages().length).toEqual(5);
});
it('should not render any page', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 4,
page: 3,
......@@ -310,14 +292,13 @@ describe('Pagination component', () => {
},
change: spy,
});
expect(component.$el.querySelectorAll('.page').length).toEqual(0);
expect(findPages().length).toEqual(0);
});
});
describe('spread operator', () => {
it('should render', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 4,
page: 3,
......@@ -328,12 +309,15 @@ describe('Pagination component', () => {
},
change: spy,
});
expect(component.$el.querySelector('.separator').textContent.trim()).toEqual('...');
expect(
findSeparator()
.text()
.trim(),
).toEqual('...');
});
it('should not render', () => {
component = mountComponent({
mountComponent({
pageInfo: {
nextPage: 4,
page: 3,
......@@ -344,8 +328,7 @@ describe('Pagination component', () => {
},
change: spy,
});
expect(component.$el.querySelector('.separator')).toBeNull();
expect(findSeparator().exists()).toBe(false);
});
});
});
......
......@@ -537,7 +537,6 @@ Project:
- external_webhook_token
- pages_https_only
- merge_requests_disable_committers_approval
- merge_requests_require_code_owner_approval
- require_password_to_approve
ProjectTracingSetting:
- external_url
......
......@@ -130,5 +130,13 @@
end
end
end
context 'when instance has configured kubernetes cluster' do
let!(:instance_cluster) { create(:cluster, :provided_by_user, :instance) }
it 'returns the Kubernetes platform' do
is_expected.to eq(instance_cluster.platform_kubernetes)
end
end
end
end
......@@ -118,14 +118,13 @@
post api("/features/#{feature_name}", admin), params: { value: 'true', user: user.username, feature_group: 'perf_team' }
expect(response).to have_gitlab_http_status(201)
expect(json_response).to eq(
'name' => 'my_feature',
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'groups', 'value' => ['perf_team'] },
{ 'key' => 'actors', 'value' => ["User:#{user.id}"] }
])
expect(json_response['name']).to eq('my_feature')
expect(json_response['state']).to eq('conditional')
expect(json_response['gates']).to contain_exactly(
{ 'key' => 'boolean', 'value' => false },
{ 'key' => 'groups', 'value' => ['perf_team'] },
{ 'key' => 'actors', 'value' => ["User:#{user.id}"] }
)
end
end
......
......@@ -990,15 +990,15 @@
dependencies:
vue-eslint-parser "^6.0.4"
 
"@gitlab/svgs@^1.78.0":
version "1.78.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.78.0.tgz#469493bd6cdd254eb5d1271edeab22bbbee2f4c4"
integrity sha512-dBgEB/Q4FRD0NapmNrD86DF1FsV0uSgTx0UOJloHnGE2DNR2P1HQrCmLW2fX+QgN4P9CDAzdi2buVHuholofWw==
"@gitlab/ui@5.36.0":
version "5.36.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-5.36.0.tgz#3087b23c138ad1c222f6b047e533f253371bc618"
integrity sha512-XXWUYZbRItKh9N92Vxql04BJ05uW5HlOuTCkD+lMbUgneqYTgVoKGH8d9kD++Jy7q8l5+AfzjboUn2n9sbQMZA==
"@gitlab/svgs@^1.79.0":
version "1.79.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.79.0.tgz#7e79666118d6adc0247bdb3b3b6b2b299aa5a439"
integrity sha512-0pTUviQqwyaKBOB6OL7Mmr2dQn/dGB03XslBMtL9lFZz1baB7d6xf+zxFU0GBAJUJan397IbBddE1jjUAQT8Fw==
"@gitlab/ui@6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-6.0.0.tgz#1d347fca1752732226f9b61b9fcbd8b60982b7cf"
integrity sha512-d37M+4MJen2dLp/svPDBcPVYZi4mgl5Gj01SPM7TeqtBl6gnps9KSjRiYd4P0FBPTbt3QQ8k2qkQ8uTi2q/o3w==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.2.1"
......
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