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
gem 'capybara', '~> 3.22.0'
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 'email_spec', '~> 2.2.0'
......
......@@ -143,8 +143,7 @@ GEM
cause (0.1)
character_set (1.1.2)
charlock_holmes (0.7.6)
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
childprocess (3.0.0)
chunky_png (1.3.5)
citrus (3.0.2)
claide (1.0.3)
......@@ -286,7 +285,7 @@ GEM
fast_blank (1.0.0)
fast_gettext (1.6.0)
ffaker (2.10.0)
ffi (1.11.1)
ffi (1.11.3)
flipper (0.17.1)
flipper-active_record (0.17.1)
activerecord (>= 4.2, < 7)
......@@ -957,9 +956,9 @@ GEM
seed-fu (2.3.7)
activerecord (>= 3.1)
activesupport (>= 3.1)
selenium-webdriver (3.141.0)
childprocess (~> 0.5)
rubyzip (~> 1.2, >= 1.2.2)
selenium-webdriver (3.142.6)
childprocess (>= 0.5, < 4.0)
rubyzip (>= 1.2.2)
sentry-raven (2.9.0)
faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9)
......@@ -1326,7 +1325,7 @@ DEPENDENCIES
sassc-rails (~> 2.1.0)
scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7)
selenium-webdriver (~> 3.141)
selenium-webdriver (~> 3.142)
sentry-raven (~> 2.9)
settingslogic (~> 2.0.9)
shoulda-matchers (~> 4.0.1)
......
......@@ -20,7 +20,6 @@ class UploadsController < ApplicationController
skip_before_action :authenticate_user!
before_action :upload_mount_satisfied?
before_action :find_model
before_action :authorize_access!, only: [:show]
before_action :authorize_create_access!, only: [:create, :authorize]
before_action :verify_workhorse_api!, only: [:authorize]
......
---
title: removes references of BoardService
merge_request: 20881
author: nuwe1
type: other
# frozen_string_literal: true
# rubocop: disable Cop/PutProjectRoutesUnderScope
resources :projects, only: [:index, :new, :create]
draw :git_http
get '/projects/:id' => 'projects#resolve'
# rubocop: enable Cop/PutProjectRoutesUnderScope
constraints(::Constraints::ProjectUrlConstrainer.new) do
# If the route has a wildcard segment, the segment has a regex constraint,
......@@ -210,6 +212,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
# 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
#
......@@ -522,6 +528,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
draw :wiki
draw :repository
# All new routes should go under /-/ scope.
# Look for scope '-' at the top of the file.
# rubocop: enable Cop/PutProjectRoutesUnderScope
# Legacy routes.
# Introduced in 12.0.
# Should be removed with https://gitlab.com/gitlab-org/gitlab/issues/28848.
......@@ -533,6 +543,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
:cycle_analytics, :mattermost, :variables, :triggers)
end
# rubocop: disable Cop/PutProjectRoutesUnderScope
resources(:projects,
path: '/',
constraints: { id: Gitlab::PathRegex.project_route_regex },
......@@ -554,5 +565,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
put :new_issuable_address
end
end
# rubocop: enable Cop/PutProjectRoutesUnderScope
end
end
......@@ -221,7 +221,7 @@ users are, how much automation you use, mirroring, and repo/change size.
### 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
- **Status:** Work-in-progress
- **Known Issues:** For the latest list of known performance issues head
......
......@@ -25,8 +25,7 @@ GEM
capybara-screenshot (1.0.18)
capybara (>= 1.0, < 3)
launchy
childprocess (0.9.0)
ffi (~> 1.0, >= 1.0.11)
childprocess (3.0.0)
coderay (1.1.2)
concurrent-ruby (1.1.5)
debase (0.2.4.1)
......@@ -95,9 +94,9 @@ GEM
ruby-debug-ide (0.7.0)
rake (>= 0.8.1)
rubyzip (1.2.2)
selenium-webdriver (3.141.0)
childprocess (~> 0.5)
rubyzip (~> 1.2, >= 1.2.2)
selenium-webdriver (3.142.6)
childprocess (>= 0.5, < 4.0)
rubyzip (>= 1.2.2)
thread_safe (0.3.6)
tzinfo (1.2.5)
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'
require_relative 'cop/avoid_route_redirect_leading_slash'
require_relative 'cop/line_break_around_conditional_block'
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_concurrent_foreign_key'
require_relative 'cop/migration/add_concurrent_index'
......
import Vue from 'vue';
import $ from 'jquery';
import { mount } from '@vue/test-utils';
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 {
mockConfig,
mockLabels,
} from '../../../../../javascripts/vue_shared/components/sidebar/labels_select/mock_data';
const labelStyles = {
textColor: '#FFFFFF',
color: '#BADA55',
};
const createComponent = (
labels = mockLabels,
labelFilterBasePath = mockConfig.labelFilterBasePath,
) => {
const Component = Vue.extend(dropdownValueComponent);
return mountComponent(Component, {
labels,
labelFilterBasePath,
enableScopedLabels: true,
labels.forEach(label => Object.assign(label, labelStyles));
return mount(DropdownValueComponent, {
propsData: {
labels,
labelFilterBasePath,
enableScopedLabels: true,
},
attachToDocument: true,
sync: false,
});
};
......@@ -30,7 +37,7 @@ describe('DropdownValueComponent', () => {
});
afterEach(() => {
vm.$destroy();
vm.destroy();
});
describe('computed', () => {
......@@ -38,12 +45,12 @@ describe('DropdownValueComponent', () => {
it('returns true if `labels` prop is empty', () => {
const vmEmptyLabels = createComponent([]);
expect(vmEmptyLabels.isEmpty).toBe(true);
vmEmptyLabels.$destroy();
expect(vmEmptyLabels.classes()).not.toContain('has-labels');
vmEmptyLabels.destroy();
});
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', () => {
describe('methods', () => {
describe('labelFilterUrl', () => {
it('returns URL string starting with labelFilterBasePath and encoded label.title', () => {
expect(
vm.labelFilterUrl({
title: 'Foo bar',
}),
).toBe('/gitlab-org/my-project/issues?label_name[]=Foo%20bar');
expect(vm.find(DropdownValueScopedLabel).props('labelFilterUrl')).toBe(
'/gitlab-org/my-project/issues?label_name[]=Foo%3A%3ABar',
);
});
});
describe('labelStyle', () => {
it('returns object with `color` & `backgroundColor` properties from label.textColor & label.color', () => {
const label = {
textColor: '#FFFFFF',
color: '#BADA55',
};
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);
expect(vm.find(DropdownValueScopedLabel).props('labelStyle')).toEqual({
color: labelStyles.textColor,
backgroundColor: labelStyles.color,
});
});
});
describe('showScopedLabels', () => {
it('returns true if the label is scoped label', () => {
expect(vm.showScopedLabels(mockLabels[1])).toBe(true);
});
it('returns false when label is a regular label', () => {
expect(vm.showScopedLabels(mockLabels[0])).toBe(false);
expect(vm.findAll(DropdownValueScopedLabel).length).toEqual(1);
});
});
});
describe('template', () => {
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(
true,
);
expect(vm.classes()).toContain('hide-collapsed', 'value', 'issuable-show-labels');
});
it('render slot content inside component when `labels` prop is empty', () => {
const vmEmptyLabels = createComponent([]);
expect(vmEmptyLabels.$el.querySelector('.text-secondary').innerText.trim()).toBe(
mockConfig.emptyValueText,
);
vmEmptyLabels.$destroy();
expect(
vmEmptyLabels
.find('.text-secondary')
.text()
.trim(),
).toBe(mockConfig.emptyValueText);
vmEmptyLabels.destroy();
});
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',
);
});
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.getAttribute('style')).toBe('background-color: rgb(186, 218, 85);');
expect(labelEl.innerText.trim()).toBe(mockLabels[0].title);
expect(labelEl.exists()).toBe(true);
expect(labelEl.attributes('style')).toContain(
`background-color: rgb(${hexToRgb(labelStyles.color).join(', ')});`,
);
expect(labelEl.text().trim()).toBe(mockLabels[0].title);
});
describe('label is of scoped-label type', () => {
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', () => {
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.querySelector('i.fa-question-circle')).not.toBeNull();
expect(anchor.exists()).toBe(true);
expect(anchor.find('i.fa-question-circle').exists()).toBe(true);
});
});
});
......
......@@ -13,7 +13,7 @@ import '~/boards/models/list';
import store from '~/boards/stores';
import boardsStore from '~/boards/stores/boards_store';
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', () => {
let vm;
......@@ -22,8 +22,8 @@ describe('Board card', () => {
beforeEach(done => {
mock = new MockAdapter(axios);
mock.onAny().reply(boardsMockInterceptor);
setMockEndpoints();
gl.boardService = mockBoardService();
boardsStore.create();
boardsStore.detail.issue = {};
......
import BoardService from '~/boards/services/board_service';
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 = {
id: 1,
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