Commit b78730d2 authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖

Merge branch 'ce-to-ee-2018-11-05' into 'master'

CE upstream - 2018-11-05 11:22 UTC

See merge request gitlab-org/gitlab-ee!8228
parents 8a96d93e 6372fe21
......@@ -109,6 +109,8 @@ module IconsHelper
def file_type_icon_class(type, mode, name)
if type == 'folder'
icon_class = 'folder'
elsif type == 'archive'
icon_class = 'archive'
elsif mode == '120000'
icon_class = 'share'
else
......
......@@ -31,11 +31,21 @@ module TreeHelper
# mode - File unix mode
# name - File name
def tree_icon(type, mode, name)
icon("#{file_type_icon_class(type, mode, name)} fw")
icon([file_type_icon_class(type, mode, name), 'fw'])
end
def tree_hex_class(content)
"file_#{hexdigest(content.name)}"
# Using Rails `*_path` methods can be slow, especially when generating
# many paths, as with a repository tree that has thousands of items.
def fast_project_blob_path(project, blob_path)
Addressable::URI.escape(
File.join(relative_url_root, project.path_with_namespace, 'blob', blob_path)
)
end
def fast_project_tree_path(project, tree_path)
Addressable::URI.escape(
File.join(relative_url_root, project.path_with_namespace, 'tree', tree_path)
)
end
# Simple shortcut to File.join
......@@ -142,4 +152,8 @@ module TreeHelper
def selected_branch
@branch_name || tree_edit_branch
end
def relative_url_root
Gitlab.config.gitlab.relative_url_root.presence || '/'
end
end
- is_lfs_blob = @lfs_blob_ids.include?(blob_item.id)
%tr{ class: "tree-item #{tree_hex_class(blob_item)}" }
%td.tree-item-file-name
= tree_icon(type, blob_item.mode, blob_item.name)
- file_name = blob_item.name
= link_to project_blob_path(@project, tree_join(@id || @commit.id, blob_item.name)), class: 'str-truncated', title: file_name do
%span= file_name
- if is_lfs_blob
%span.badge.label-lfs.prepend-left-5 LFS
%td.d-none.d-sm-table-cell.tree-commit
%td.tree-time-ago.cgray.text-right
= render 'projects/tree/spinner'
%span.log_loading.hide
%i.fa.fa-spinner.fa-spin
Loading commit data...
%tr.tree-item
%td.tree-item-file-name
%i.fa.fa-archive.fa-fw
= submodule_link(submodule_item, @ref)
%td
%td.d-none.d-sm-table-cell
%tr{ class: "tree-item #{tree_hex_class(tree_item)}" }
%td.tree-item-file-name
= tree_icon(type, tree_item.mode, tree_item.name)
- path = flatten_tree(@path, tree_item)
= link_to project_tree_path(@project, tree_join(@id || @commit.id, path)), class: 'str-truncated', title: path do
%span= path
%td.d-none.d-sm-table-cell.tree-commit
%td.tree-time-ago.text-right
= render 'projects/tree/spinner'
- if tree_row.type == :tree
= render partial: 'projects/tree/tree_item', object: tree_row, as: 'tree_item', locals: { type: 'folder' }
- elsif tree_row.type == :blob
= render partial: 'projects/tree/blob_item', object: tree_row, as: 'blob_item', locals: { type: 'file' }
- elsif tree_row.type == :commit
= render partial: 'projects/tree/submodule_item', object: tree_row, as: 'submodule_item'
- tree_row_name = tree_row.name
- tree_row_type = tree_row.type
%tr{ class: "tree-item file_#{hexdigest(tree_row_name)}" }
%td.tree-item-file-name
- if tree_row_type == :tree
= tree_icon('folder', tree_row.mode, tree_row.name)
- path = flatten_tree(@path, tree_row)
%a.str-truncated{ href: fast_project_tree_path(@project, tree_join(@id || @commit.id, path)), title: path }
%span= path
- elsif tree_row_type == :blob
= tree_icon('file', tree_row.mode, tree_row_name)
%a.str-truncated{ href: fast_project_blob_path(@project, tree_join(@id || @commit.id, tree_row_name)), title: tree_row_name }
%span= tree_row_name
- if @lfs_blob_ids.include?(tree_row.id)
%span.badge.label-lfs.prepend-left-5 LFS
- elsif tree_row_type == :commit
= tree_icon('archive', tree_row.mode, tree_row.name)
= submodule_link(tree_row, @ref)
%td.d-none.d-sm-table-cell.tree-commit
%td.tree-time-ago.text-right
%span.log_loading.hide
%i.fa.fa-spinner.fa-spin
Loading commit data...
---
title: Bump KUBERNETES_VERSION for Auto DevOps to latest 1.10 series
merge_request: 22757
author:
type: other
---
title: Improve performance of tree rendering in repositories with lots of items
merge_request:
author:
type: performance
......@@ -94,6 +94,7 @@ The following table depicts the various user permission levels in a project.
| Manage GitLab Pages | | | | ✓ | ✓ |
| Manage GitLab Pages domains and certificates | | | | ✓ | ✓ |
| Remove GitLab Pages | | | | | ✓ |
| View GitLab Pages protected by [access control](../administration/pages/index.md#access-control) | ✓ | ✓ | ✓ | ✓ | ✓ |
| Manage clusters | | | | ✓ | ✓ |
| Manage license policy **[ULTIMATE]** | | | | ✓ | ✓ |
| Edit comments (posted by any user) | | | | ✓ | ✓ |
......@@ -205,7 +206,7 @@ They will, like usual users, receive a role in the project or group with all
the abilities that are mentioned in the table above. They cannot however create
groups or projects, and they have the same access as logged out users in all
other cases.
An administrator can flag a user as external [through the API](../api/users.md)
or by checking the checkbox on the admin panel. As an administrator, navigate
to **Admin > Users** to create a new user or edit an existing one. There, you
......@@ -216,7 +217,7 @@ by an administrator under **Admin > Application Settings**.
### Default internal users
The "Internal users" field allows specifying an e-mail address regex pattern to identify default internal users.
The "Internal users" field allows specifying an e-mail address regex pattern to identify default internal users.
New users whose email address matches the regex pattern will be set to internal by default rather than an external collaborator.
......
......@@ -49,7 +49,7 @@ variables:
POSTGRES_ENABLED: "true"
POSTGRES_DB: $CI_ENVIRONMENT_SLUG
KUBERNETES_VERSION: 1.8.6
KUBERNETES_VERSION: 1.10.9
HELM_VERSION: 2.11.0
DOCKER_DRIVER: overlay2
......
......@@ -52,14 +52,18 @@ module QA
end
def api_get
url = Runtime::API::Request.new(api_client, api_get_path).url
process_api_response(parse_body(api_get_from(api_get_path)))
end
def api_get_from(get_path)
url = Runtime::API::Request.new(api_client, get_path).url
response = get(url)
unless response.code == HTTP_STATUS_OK
raise ResourceNotFoundError, "Resource at #{url} could not be found (#{response.code}): `#{response}`."
end
process_api_response(parse_body(response))
response
end
def api_post
......
......@@ -15,44 +15,17 @@ module QA
end
end
def visit_project_with_retry
# The user intermittently fails to stay signed in after visiting the
# project page. The new user is registered and then signs in and a
# screenshot shows that signing in was successful. Then the project
# page is visited but a screenshot shows the user is no longer signed
# in. It's difficult to reproduce locally but GDK logs don't seem to
# show anything unexpected. This method attempts to work around the
# problem and capture data to help troubleshoot.
Capybara::Screenshot.screenshot_and_save_page
start = Time.now
while Time.now - start < 20
push.project.visit!
puts "Visited project page"
Capybara::Screenshot.screenshot_and_save_page
return if Page::Main::Menu.act { has_personal_area?(wait: 0) }
puts "Not signed in. Attempting to sign in again."
Capybara::Screenshot.screenshot_and_save_page
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform do |login|
login.sign_in_using_credentials(user)
end
end
raise "Failed to load project page and stay logged in"
end
def fabricate!
populate(:push, :user)
visit_project_with_retry
# Sign out as admin and sign is as the fork user
Page::Main::Menu.perform(&:sign_out)
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform do |login|
login.sign_in_using_credentials(user)
end
push.project.visit!
Page::Project::Show.perform(&:fork_project)
......
......@@ -50,6 +50,42 @@ module QA
end
end
end
def fabricate_via_api!
resource_web_url(api_get)
rescue ResourceNotFoundError
super
end
def api_get_path
"/users/#{fetch_id(username)}"
end
def api_post_path
'/users'
end
def api_post_body
{
email: email,
password: password,
username: username,
name: name,
skip_confirmation: true
}
end
private
def fetch_id(username)
users = parse_body(api_get_from("/users?username=#{username}"))
unless users.size == 1 && users.first[:username] == username
raise ResourceNotFoundError, "Expected one user with username #{username} but found: `#{users}`."
end
users.first[:id]
end
end
end
end
......
......@@ -5,7 +5,7 @@ module QA
it 'user registers and logs in' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Factory::Resource::User.fabricate!
Factory::Resource::User.fabricate_via_browser_ui!
# TODO, since `Signed in successfully` message was removed
# this is the only way to tell if user is signed in correctly.
......
......@@ -5,18 +5,16 @@ module QA
describe 'Add project member' do
it 'user adds project member' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
Page::Main::Login.perform(&:sign_in_using_credentials)
user = Factory::Resource::User.fabricate!
Page::Main::Menu.perform { |main| main.sign_out }
Page::Main::Login.act { sign_in_using_credentials }
project = Factory::Resource::Project.fabricate! do |resource|
resource.name = 'add-member-project'
end
project.visit!
Page::Project::Menu.act { click_members_settings }
Page::Project::Menu.perform(&:click_members_settings)
Page::Project::Settings::Members.perform do |page|
page.add_member(user.username)
end
......
# frozen_string_literal: true
describe QA::Factory::Resource::User do
describe "#fabricate_via_api!" do
Response = Struct.new(:code, :body)
it 'fetches an existing user' do
existing_users = [
{
id: '0',
name: 'name',
username: 'name',
web_url: ''
}
]
users_response = Response.new('200', JSON.dump(existing_users))
single_user_response = Response.new('200', JSON.dump(existing_users.first))
expect(subject).to receive(:api_get_from).with("/users?username=name").and_return(users_response)
expect(subject).to receive(:api_get_from).with("/users/0").and_return(single_user_response)
subject.username = 'name'
subject.fabricate_via_api!
expect(subject.api_response).to eq(existing_users.first)
end
it 'tries to create a user if it does not exist' do
expect(subject).to receive(:api_get_from).with("/users?username=foo").and_return(Response.new('200', '[]'))
expect(subject).to receive(:api_post).and_return({ web_url: '' })
subject.username = 'foo'
subject.fabricate_via_api!
end
end
end
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe TreeHelper do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:sha) { 'ce369011c189f62c815f5971d096b26759bab0d1' }
let(:sha) { 'c1c67abbaf91f624347bb3ae96eabe3a1b742478' }
describe '.render_tree' do
before do
......@@ -32,6 +32,49 @@ describe TreeHelper do
end
end
describe '.fast_project_blob_path' do
it 'generates the same path as project_blob_path' do
blob_path = repository.tree(sha, 'with space').entries.first.path
fast_path = fast_project_blob_path(project, blob_path)
std_path = project_blob_path(project, blob_path)
expect(fast_path).to eq(std_path)
end
it 'generates the same path with encoded file names' do
tree = repository.tree(sha, 'encoding')
blob_path = tree.entries.find { |entry| entry.path == 'encoding/テスト.txt' }.path
fast_path = fast_project_blob_path(project, blob_path)
std_path = project_blob_path(project, blob_path)
expect(fast_path).to eq(std_path)
end
it 'respects a configured relative URL' do
allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return('/gitlab/root')
blob_path = repository.tree(sha, '').entries.first.path
fast_path = fast_project_blob_path(project, blob_path)
expect(fast_path).to start_with('/gitlab/root')
end
end
describe '.fast_project_tree_path' do
let(:tree_path) { repository.tree(sha, 'with space').path }
let(:fast_path) { fast_project_tree_path(project, tree_path) }
let(:std_path) { project_tree_path(project, tree_path) }
it 'generates the same path as project_tree_path' do
expect(fast_path).to eq(std_path)
end
it 'respects a configured relative URL' do
allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return('/gitlab/root')
expect(fast_path).to start_with('/gitlab/root')
end
end
describe 'flatten_tree' do
let(:tree) { repository.tree(sha, 'files') }
let(:root_path) { 'files' }
......
require 'spec_helper'
describe 'projects/tree/_blob_item' do
describe 'projects/tree/_tree_row' do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:blob_item) { Gitlab::Git::Tree.where(repository, SeedRepo::Commit::ID, 'files/ruby').first }
......@@ -31,10 +31,7 @@ describe 'projects/tree/_blob_item' do
end
end
def render_partial(blob_item)
render partial: 'projects/tree/blob_item', locals: {
blob_item: blob_item,
type: 'blob'
}
def render_partial(items)
render partial: 'projects/tree/tree_row', collection: [items].flatten
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