Commit 4f05a630 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 7cdd70dc
...@@ -401,7 +401,7 @@ group :test do ...@@ -401,7 +401,7 @@ group :test do
gem 'capybara', '~> 3.22.0' gem 'capybara', '~> 3.22.0'
gem 'capybara-screenshot', '~> 1.0.22' gem 'capybara-screenshot', '~> 1.0.22'
gem 'selenium-webdriver', '~> 3.141' gem 'selenium-webdriver', '~> 3.142'
gem 'shoulda-matchers', '~> 4.0.1', require: false gem 'shoulda-matchers', '~> 4.0.1', require: false
gem 'email_spec', '~> 2.2.0' gem 'email_spec', '~> 2.2.0'
......
...@@ -143,8 +143,7 @@ GEM ...@@ -143,8 +143,7 @@ GEM
cause (0.1) cause (0.1)
character_set (1.1.2) character_set (1.1.2)
charlock_holmes (0.7.6) charlock_holmes (0.7.6)
childprocess (0.9.0) childprocess (3.0.0)
ffi (~> 1.0, >= 1.0.11)
chunky_png (1.3.5) chunky_png (1.3.5)
citrus (3.0.2) citrus (3.0.2)
claide (1.0.3) claide (1.0.3)
...@@ -286,7 +285,7 @@ GEM ...@@ -286,7 +285,7 @@ GEM
fast_blank (1.0.0) fast_blank (1.0.0)
fast_gettext (1.6.0) fast_gettext (1.6.0)
ffaker (2.10.0) ffaker (2.10.0)
ffi (1.11.1) ffi (1.11.3)
flipper (0.17.1) flipper (0.17.1)
flipper-active_record (0.17.1) flipper-active_record (0.17.1)
activerecord (>= 4.2, < 7) activerecord (>= 4.2, < 7)
...@@ -957,9 +956,9 @@ GEM ...@@ -957,9 +956,9 @@ GEM
seed-fu (2.3.7) seed-fu (2.3.7)
activerecord (>= 3.1) activerecord (>= 3.1)
activesupport (>= 3.1) activesupport (>= 3.1)
selenium-webdriver (3.141.0) selenium-webdriver (3.142.6)
childprocess (~> 0.5) childprocess (>= 0.5, < 4.0)
rubyzip (~> 1.2, >= 1.2.2) rubyzip (>= 1.2.2)
sentry-raven (2.9.0) sentry-raven (2.9.0)
faraday (>= 0.7.6, < 1.0) faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9) settingslogic (2.0.9)
...@@ -1326,7 +1325,7 @@ DEPENDENCIES ...@@ -1326,7 +1325,7 @@ DEPENDENCIES
sassc-rails (~> 2.1.0) sassc-rails (~> 2.1.0)
scss_lint (~> 0.56.0) scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7) seed-fu (~> 2.3.7)
selenium-webdriver (~> 3.141) selenium-webdriver (~> 3.142)
sentry-raven (~> 2.9) sentry-raven (~> 2.9)
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
shoulda-matchers (~> 4.0.1) shoulda-matchers (~> 4.0.1)
......
...@@ -20,7 +20,6 @@ class UploadsController < ApplicationController ...@@ -20,7 +20,6 @@ class UploadsController < ApplicationController
skip_before_action :authenticate_user! skip_before_action :authenticate_user!
before_action :upload_mount_satisfied? before_action :upload_mount_satisfied?
before_action :find_model
before_action :authorize_access!, only: [:show] before_action :authorize_access!, only: [:show]
before_action :authorize_create_access!, only: [:create, :authorize] before_action :authorize_create_access!, only: [:create, :authorize]
before_action :verify_workhorse_api!, only: [:authorize] before_action :verify_workhorse_api!, only: [:authorize]
......
---
title: removes references of BoardService
merge_request: 20881
author: nuwe1
type: other
# frozen_string_literal: true # frozen_string_literal: true
# rubocop: disable Cop/PutProjectRoutesUnderScope
resources :projects, only: [:index, :new, :create] resources :projects, only: [:index, :new, :create]
draw :git_http draw :git_http
get '/projects/:id' => 'projects#resolve' get '/projects/:id' => 'projects#resolve'
# rubocop: enable Cop/PutProjectRoutesUnderScope
constraints(::Constraints::ProjectUrlConstrainer.new) do constraints(::Constraints::ProjectUrlConstrainer.new) do
# If the route has a wildcard segment, the segment has a regex constraint, # If the route has a wildcard segment, the segment has a regex constraint,
...@@ -210,6 +212,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -210,6 +212,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end end
# End of the /-/ scope. # End of the /-/ scope.
# All new routes should go under /-/ scope.
# Look for scope '-' at the top of the file.
# rubocop: disable Cop/PutProjectRoutesUnderScope
# #
# Templates # Templates
# #
...@@ -522,6 +528,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -522,6 +528,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
draw :wiki draw :wiki
draw :repository draw :repository
# All new routes should go under /-/ scope.
# Look for scope '-' at the top of the file.
# rubocop: enable Cop/PutProjectRoutesUnderScope
# Legacy routes. # Legacy routes.
# Introduced in 12.0. # Introduced in 12.0.
# Should be removed with https://gitlab.com/gitlab-org/gitlab/issues/28848. # Should be removed with https://gitlab.com/gitlab-org/gitlab/issues/28848.
...@@ -533,6 +543,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -533,6 +543,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
:cycle_analytics, :mattermost, :variables, :triggers) :cycle_analytics, :mattermost, :variables, :triggers)
end end
# rubocop: disable Cop/PutProjectRoutesUnderScope
resources(:projects, resources(:projects,
path: '/', path: '/',
constraints: { id: Gitlab::PathRegex.project_route_regex }, constraints: { id: Gitlab::PathRegex.project_route_regex },
...@@ -554,5 +565,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do ...@@ -554,5 +565,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
put :new_issuable_address put :new_issuable_address
end end
end end
# rubocop: enable Cop/PutProjectRoutesUnderScope
end end
end end
...@@ -221,7 +221,7 @@ users are, how much automation you use, mirroring, and repo/change size. ...@@ -221,7 +221,7 @@ users are, how much automation you use, mirroring, and repo/change size.
### 5,000 User Configuration ### 5,000 User Configuration
- **Supported Users (approximate):** 50,000 - **Supported Users (approximate):** 5,000
- **Test RPS Rates:** API: 100 RPS, Web: 10 RPS, Git: 10 RPS - **Test RPS Rates:** API: 100 RPS, Web: 10 RPS, Git: 10 RPS
- **Status:** Work-in-progress - **Status:** Work-in-progress
- **Known Issues:** For the latest list of known performance issues head - **Known Issues:** For the latest list of known performance issues head
......
...@@ -25,8 +25,7 @@ GEM ...@@ -25,8 +25,7 @@ GEM
capybara-screenshot (1.0.18) capybara-screenshot (1.0.18)
capybara (>= 1.0, < 3) capybara (>= 1.0, < 3)
launchy launchy
childprocess (0.9.0) childprocess (3.0.0)
ffi (~> 1.0, >= 1.0.11)
coderay (1.1.2) coderay (1.1.2)
concurrent-ruby (1.1.5) concurrent-ruby (1.1.5)
debase (0.2.4.1) debase (0.2.4.1)
...@@ -95,9 +94,9 @@ GEM ...@@ -95,9 +94,9 @@ GEM
ruby-debug-ide (0.7.0) ruby-debug-ide (0.7.0)
rake (>= 0.8.1) rake (>= 0.8.1)
rubyzip (1.2.2) rubyzip (1.2.2)
selenium-webdriver (3.141.0) selenium-webdriver (3.142.6)
childprocess (~> 0.5) childprocess (>= 0.5, < 4.0)
rubyzip (~> 1.2, >= 1.2.2) rubyzip (>= 1.2.2)
thread_safe (0.3.6) thread_safe (0.3.6)
tzinfo (1.2.5) tzinfo (1.2.5)
thread_safe (~> 0.1) thread_safe (~> 0.1)
......
# frozen_string_literal: true
module RuboCop
module Cop
# Checks for a project routes outside '/-/' scope.
# For more information see: https://gitlab.com/gitlab-org/gitlab/issues/29572
class PutProjectRoutesUnderScope < RuboCop::Cop::Cop
MSG = 'Put new project routes under /-/ scope'
def_node_matcher :dash_scope?, <<~PATTERN
(:send nil? :scope (:str "-"))
PATTERN
def on_send(node)
return unless in_project_routes?(node)
return unless resource?(node)
return unless outside_scope?(node)
add_offense(node)
end
def outside_scope?(node)
node.each_ancestor(:block).none? do |parent|
dash_scope?(parent.to_a.first)
end
end
def in_project_routes?(node)
path = node.location.expression.source_buffer.name
dirname = File.dirname(path)
filename = File.basename(path)
dirname.end_with?('config/routes') &&
filename.end_with?('project.rb')
end
def resource?(node)
node.method_name == :resource ||
node.method_name == :resources
end
end
end
end
...@@ -14,6 +14,7 @@ require_relative 'cop/avoid_break_from_strong_memoize' ...@@ -14,6 +14,7 @@ require_relative 'cop/avoid_break_from_strong_memoize'
require_relative 'cop/avoid_route_redirect_leading_slash' require_relative 'cop/avoid_route_redirect_leading_slash'
require_relative 'cop/line_break_around_conditional_block' require_relative 'cop/line_break_around_conditional_block'
require_relative 'cop/prefer_class_methods_over_module' require_relative 'cop/prefer_class_methods_over_module'
require_relative 'cop/put_project_routes_under_scope'
require_relative 'cop/migration/add_column' require_relative 'cop/migration/add_column'
require_relative 'cop/migration/add_concurrent_foreign_key' require_relative 'cop/migration/add_concurrent_foreign_key'
require_relative 'cop/migration/add_concurrent_index' require_relative 'cop/migration/add_concurrent_index'
......
import Vue from 'vue'; import { mount } from '@vue/test-utils';
import $ from 'jquery'; import { hexToRgb } from '~/lib/utils/color_utils';
import DropdownValueComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_value.vue';
import DropdownValueScopedLabel from '~/vue_shared/components/sidebar/labels_select/dropdown_value_scoped_label.vue';
import dropdownValueComponent from '~/vue_shared/components/sidebar/labels_select/dropdown_value.vue';
import mountComponent from 'helpers/vue_mount_component_helper';
import { import {
mockConfig, mockConfig,
mockLabels, mockLabels,
} from '../../../../../javascripts/vue_shared/components/sidebar/labels_select/mock_data'; } from '../../../../../javascripts/vue_shared/components/sidebar/labels_select/mock_data';
const labelStyles = {
textColor: '#FFFFFF',
color: '#BADA55',
};
const createComponent = ( const createComponent = (
labels = mockLabels, labels = mockLabels,
labelFilterBasePath = mockConfig.labelFilterBasePath, labelFilterBasePath = mockConfig.labelFilterBasePath,
) => { ) => {
const Component = Vue.extend(dropdownValueComponent); labels.forEach(label => Object.assign(label, labelStyles));
return mountComponent(Component, { return mount(DropdownValueComponent, {
propsData: {
labels, labels,
labelFilterBasePath, labelFilterBasePath,
enableScopedLabels: true, enableScopedLabels: true,
},
attachToDocument: true,
sync: false,
}); });
}; };
...@@ -30,7 +37,7 @@ describe('DropdownValueComponent', () => { ...@@ -30,7 +37,7 @@ describe('DropdownValueComponent', () => {
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); vm.destroy();
}); });
describe('computed', () => { describe('computed', () => {
...@@ -38,12 +45,12 @@ describe('DropdownValueComponent', () => { ...@@ -38,12 +45,12 @@ describe('DropdownValueComponent', () => {
it('returns true if `labels` prop is empty', () => { it('returns true if `labels` prop is empty', () => {
const vmEmptyLabels = createComponent([]); const vmEmptyLabels = createComponent([]);
expect(vmEmptyLabels.isEmpty).toBe(true); expect(vmEmptyLabels.classes()).not.toContain('has-labels');
vmEmptyLabels.$destroy(); vmEmptyLabels.destroy();
}); });
it('returns false if `labels` prop is empty', () => { it('returns false if `labels` prop is empty', () => {
expect(vm.isEmpty).toBe(false); expect(vm.classes()).toContain('has-labels');
}); });
}); });
}); });
...@@ -51,88 +58,71 @@ describe('DropdownValueComponent', () => { ...@@ -51,88 +58,71 @@ describe('DropdownValueComponent', () => {
describe('methods', () => { describe('methods', () => {
describe('labelFilterUrl', () => { describe('labelFilterUrl', () => {
it('returns URL string starting with labelFilterBasePath and encoded label.title', () => { it('returns URL string starting with labelFilterBasePath and encoded label.title', () => {
expect( expect(vm.find(DropdownValueScopedLabel).props('labelFilterUrl')).toBe(
vm.labelFilterUrl({ '/gitlab-org/my-project/issues?label_name[]=Foo%3A%3ABar',
title: 'Foo bar', );
}),
).toBe('/gitlab-org/my-project/issues?label_name[]=Foo%20bar');
}); });
}); });
describe('labelStyle', () => { describe('labelStyle', () => {
it('returns object with `color` & `backgroundColor` properties from label.textColor & label.color', () => { it('returns object with `color` & `backgroundColor` properties from label.textColor & label.color', () => {
const label = { expect(vm.find(DropdownValueScopedLabel).props('labelStyle')).toEqual({
textColor: '#FFFFFF', color: labelStyles.textColor,
color: '#BADA55', backgroundColor: labelStyles.color,
};
const styleObj = vm.labelStyle(label);
expect(styleObj.color).toBe(label.textColor);
expect(styleObj.backgroundColor).toBe(label.color);
}); });
}); });
describe('scopedLabelsDescription', () => {
it('returns html for tooltip', () => {
const html = vm.scopedLabelsDescription(mockLabels[1]);
const $el = $.parseHTML(html);
expect($el[0]).toHaveClass('scoped-label-tooltip-title');
expect($el[2].textContent).toEqual(mockLabels[1].description);
});
}); });
describe('showScopedLabels', () => { describe('showScopedLabels', () => {
it('returns true if the label is scoped label', () => { it('returns true if the label is scoped label', () => {
expect(vm.showScopedLabels(mockLabels[1])).toBe(true); expect(vm.findAll(DropdownValueScopedLabel).length).toEqual(1);
});
it('returns false when label is a regular label', () => {
expect(vm.showScopedLabels(mockLabels[0])).toBe(false);
}); });
}); });
}); });
describe('template', () => { describe('template', () => {
it('renders component container element with classes `hide-collapsed value issuable-show-labels`', () => { it('renders component container element with classes `hide-collapsed value issuable-show-labels`', () => {
expect(vm.$el.classList.contains('hide-collapsed', 'value', 'issuable-show-labels')).toBe( expect(vm.classes()).toContain('hide-collapsed', 'value', 'issuable-show-labels');
true,
);
}); });
it('render slot content inside component when `labels` prop is empty', () => { it('render slot content inside component when `labels` prop is empty', () => {
const vmEmptyLabels = createComponent([]); const vmEmptyLabels = createComponent([]);
expect(vmEmptyLabels.$el.querySelector('.text-secondary').innerText.trim()).toBe( expect(
mockConfig.emptyValueText, vmEmptyLabels
); .find('.text-secondary')
vmEmptyLabels.$destroy(); .text()
.trim(),
).toBe(mockConfig.emptyValueText);
vmEmptyLabels.destroy();
}); });
it('renders label element with filter URL', () => { it('renders label element with filter URL', () => {
expect(vm.$el.querySelector('a').getAttribute('href')).toBe( expect(vm.find('a').attributes('href')).toBe(
'/gitlab-org/my-project/issues?label_name[]=Foo%20Label', '/gitlab-org/my-project/issues?label_name[]=Foo%20Label',
); );
}); });
it('renders label element and styles based on label details', () => { it('renders label element and styles based on label details', () => {
const labelEl = vm.$el.querySelector('a span.badge.color-label'); const labelEl = vm.find('a span.badge.color-label');
expect(labelEl).not.toBeNull(); expect(labelEl.exists()).toBe(true);
expect(labelEl.getAttribute('style')).toBe('background-color: rgb(186, 218, 85);'); expect(labelEl.attributes('style')).toContain(
expect(labelEl.innerText.trim()).toBe(mockLabels[0].title); `background-color: rgb(${hexToRgb(labelStyles.color).join(', ')});`,
);
expect(labelEl.text().trim()).toBe(mockLabels[0].title);
}); });
describe('label is of scoped-label type', () => { describe('label is of scoped-label type', () => {
it('renders a scoped-label-wrapper span to incorporate 2 anchors', () => { it('renders a scoped-label-wrapper span to incorporate 2 anchors', () => {
expect(vm.$el.querySelector('span.scoped-label-wrapper')).not.toBeNull(); expect(vm.find('span.scoped-label-wrapper').exists()).toBe(true);
}); });
it('renders anchor tag containing question icon', () => { it('renders anchor tag containing question icon', () => {
const anchor = vm.$el.querySelector('.scoped-label-wrapper a.scoped-label'); const anchor = vm.find('.scoped-label-wrapper a.scoped-label');
expect(anchor).not.toBeNull(); expect(anchor.exists()).toBe(true);
expect(anchor.querySelector('i.fa-question-circle')).not.toBeNull(); expect(anchor.find('i.fa-question-circle').exists()).toBe(true);
}); });
}); });
}); });
......
...@@ -13,7 +13,7 @@ import '~/boards/models/list'; ...@@ -13,7 +13,7 @@ import '~/boards/models/list';
import store from '~/boards/stores'; import store from '~/boards/stores';
import boardsStore from '~/boards/stores/boards_store'; import boardsStore from '~/boards/stores/boards_store';
import boardCard from '~/boards/components/board_card.vue'; import boardCard from '~/boards/components/board_card.vue';
import { listObj, boardsMockInterceptor, mockBoardService } from './mock_data'; import { listObj, boardsMockInterceptor, setMockEndpoints } from './mock_data';
describe('Board card', () => { describe('Board card', () => {
let vm; let vm;
...@@ -22,8 +22,8 @@ describe('Board card', () => { ...@@ -22,8 +22,8 @@ describe('Board card', () => {
beforeEach(done => { beforeEach(done => {
mock = new MockAdapter(axios); mock = new MockAdapter(axios);
mock.onAny().reply(boardsMockInterceptor); mock.onAny().reply(boardsMockInterceptor);
setMockEndpoints();
gl.boardService = mockBoardService();
boardsStore.create(); boardsStore.create();
boardsStore.detail.issue = {}; boardsStore.detail.issue = {};
......
import BoardService from '~/boards/services/board_service'; import BoardService from '~/boards/services/board_service';
import boardsStore from '~/boards/stores/boards_store'; import boardsStore from '~/boards/stores/boards_store';
export const setMockEndpoints = (opts = {}) => {
const boardsEndpoint = opts.boardsEndpoint || '/test/issue-boards/-/boards.json';
const listsEndpoint = opts.listsEndpoint || '/test/-/boards/1/lists';
const bulkUpdatePath = opts.bulkUpdatePath || '';
const boardId = opts.boardId || '1';
boardsStore.setEndpoints({
boardsEndpoint,
listsEndpoint,
bulkUpdatePath,
boardId,
});
};
export const boardObj = { export const boardObj = {
id: 1, id: 1,
name: 'test', name: 'test',
......
# frozen_string_literal: true
require 'spec_helper'
require 'rubocop'
require_relative '../../../rubocop/cop/put_project_routes_under_scope'
describe RuboCop::Cop::PutProjectRoutesUnderScope do
include CopHelper
subject(:cop) { described_class.new }
before do
allow(cop).to receive(:in_project_routes?).and_return(true)
end
it 'registers an offense when route is outside scope' do
expect_offense(<<~PATTERN.strip_indent)
scope '-' do
resource :issues
end
resource :notes
^^^^^^^^^^^^^^^ Put new project routes under /-/ scope
PATTERN
end
it 'does not register an offense when resource inside the scope' do
expect_no_offenses(<<~PATTERN.strip_indent)
scope '-' do
resource :issues
resource :notes
end
PATTERN
end
it 'does not register an offense when resource is deep inside the scope' do
expect_no_offenses(<<~PATTERN.strip_indent)
scope '-' do
resource :issues
resource :projects do
resource :issues do
resource :notes
end
end
end
PATTERN
end
end
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