From b35110d978d9a2061c59bcca1310b70f6f6011e1 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Wed, 13 Dec 2017 14:20:20 +0100 Subject: Move Namespace to Gitaly using OPT-OUT --- lib/gitlab/shell.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb index a22a63665be..1c48143b3b5 100644 --- a/lib/gitlab/shell.rb +++ b/lib/gitlab/shell.rb @@ -228,7 +228,8 @@ module Gitlab # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385 def add_namespace(storage, name) - Gitlab::GitalyClient.migrate(:add_namespace) do |enabled| + Gitlab::GitalyClient.migrate(:add_namespace, + status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled| if enabled gitaly_namespace_client(storage).add(name) else @@ -250,7 +251,8 @@ module Gitlab # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385 def rm_namespace(storage, name) - Gitlab::GitalyClient.migrate(:remove_namespace) do |enabled| + Gitlab::GitalyClient.migrate(:remove_namespace, + status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled| if enabled gitaly_namespace_client(storage).remove(name) else @@ -268,7 +270,8 @@ module Gitlab # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385 def mv_namespace(storage, old_name, new_name) - Gitlab::GitalyClient.migrate(:rename_namespace) do |enabled| + Gitlab::GitalyClient.migrate(:rename_namespace, + status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled| if enabled gitaly_namespace_client(storage).rename(old_name, new_name) else @@ -302,7 +305,8 @@ module Gitlab # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385 def exists?(storage, dir_name) - Gitlab::GitalyClient.migrate(:namespace_exists) do |enabled| + Gitlab::GitalyClient.migrate(:namespace_exists, + status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled| if enabled gitaly_namespace_client(storage).exists?(dir_name) else -- cgit v1.2.1 From ad9e3dfe5d3d8136ae659b4de9f37af9f6b5462f Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Thu, 14 Dec 2017 17:16:55 -0600 Subject: added katex.js and load it via webpack --- lib/gitlab/gon_helper.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index dfcdfc307b6..f91be9a7142 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -15,7 +15,6 @@ module Gitlab gon.shortcuts_path = help_page_path('shortcuts') gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class gon.katex_css_url = ActionController::Base.helpers.asset_path('katex.css') - gon.katex_js_url = ActionController::Base.helpers.asset_path('katex.js') gon.sentry_dsn = current_application_settings.clientside_sentry_dsn if current_application_settings.clientside_sentry_enabled gon.gitlab_url = Gitlab.config.gitlab.url gon.revision = Gitlab::REVISION -- cgit v1.2.1 From 78bfced3ff33ee94c5c0bfc21bb2c5a356e08396 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Wed, 20 Dec 2017 18:01:12 -0600 Subject: Removed the katex precompile steps from the application configuration --- lib/gitlab/gon_helper.rb | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb index f91be9a7142..1fe076cf909 100644 --- a/lib/gitlab/gon_helper.rb +++ b/lib/gitlab/gon_helper.rb @@ -14,7 +14,6 @@ module Gitlab gon.relative_url_root = Gitlab.config.gitlab.relative_url_root gon.shortcuts_path = help_page_path('shortcuts') gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class - gon.katex_css_url = ActionController::Base.helpers.asset_path('katex.css') gon.sentry_dsn = current_application_settings.clientside_sentry_dsn if current_application_settings.clientside_sentry_enabled gon.gitlab_url = Gitlab.config.gitlab.url gon.revision = Gitlab::REVISION -- cgit v1.2.1 From 6b0c6e69e1b249f14624550fcbca7f5ee6f51410 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Fri, 1 Dec 2017 13:58:49 +0000 Subject: Use hashed storage in the specs --- lib/api/internal.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 9285fb90cdc..b3660e4a1d0 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -13,7 +13,7 @@ module API # key_id - ssh key id for Git over SSH # user_id - user id for Git over HTTP # protocol - Git access protocol being used, e.g. HTTP or SSH - # project - project path with namespace + # project - project full_path (not path on disk) # action - git action (git-upload-pack or git-receive-pack) # changes - changes as "oldrev newrev ref", see Gitlab::ChangesList post "/allowed" do -- cgit v1.2.1 From 0478ff7cd44d291e931436b8fcd4c5c53b249741 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Thu, 8 Feb 2018 09:11:00 +0100 Subject: Handle uniqueness on fork_network_member creation Since the migration might be queued already and be rescheduled when it fails on a uniqueness error, this should help clearing the background migration queue faster. --- .../create_fork_network_memberships_range.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/background_migration/create_fork_network_memberships_range.rb b/lib/gitlab/background_migration/create_fork_network_memberships_range.rb index 03b17b319fa..1b4a9e8a194 100644 --- a/lib/gitlab/background_migration/create_fork_network_memberships_range.rb +++ b/lib/gitlab/background_migration/create_fork_network_memberships_range.rb @@ -14,6 +14,14 @@ module Gitlab def perform(start_id, end_id) log("Creating memberships for forks: #{start_id} - #{end_id}") + insert_members(start_id, end_id) + + if missing_members?(start_id, end_id) + BackgroundMigrationWorker.perform_in(RESCHEDULE_DELAY, "CreateForkNetworkMembershipsRange", [start_id, end_id]) + end + end + + def insert_members(start_id, end_id) ActiveRecord::Base.connection.execute <<~INSERT_MEMBERS INSERT INTO fork_network_members (fork_network_id, project_id, forked_from_project_id) @@ -33,10 +41,9 @@ module Gitlab WHERE existing_members.project_id = forked_project_links.forked_to_project_id ) INSERT_MEMBERS - - if missing_members?(start_id, end_id) - BackgroundMigrationWorker.perform_in(RESCHEDULE_DELAY, "CreateForkNetworkMembershipsRange", [start_id, end_id]) - end + rescue ActiveRecord::RecordNotUnique => e + # `fork_network_member` was created concurrently in another migration + log(e.message) end def missing_members?(start_id, end_id) -- cgit v1.2.1 From b7cd99c376c2f953f30a4bf982b69780e3d6985b Mon Sep 17 00:00:00 2001 From: Markus Koller Date: Fri, 22 Dec 2017 16:54:55 +0100 Subject: Allow including custom attributes in API responses --- lib/api/entities.rb | 5 +++++ lib/api/groups.rb | 29 ++++++++++++++++++++++++++--- lib/api/helpers/custom_attributes.rb | 28 ++++++++++++++++++++++++++++ lib/api/projects.rb | 19 ++++++++++++++++--- lib/api/users.rb | 9 ++++++++- 5 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 lib/api/helpers/custom_attributes.rb (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 7838de13c56..dc8e2b26316 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -22,6 +22,7 @@ module API end expose :avatar_path, if: ->(user, options) { options.fetch(:only_path, false) && user.avatar_path } + expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes expose :web_url do |user, options| Gitlab::Routing.url_helpers.user_url(user) @@ -109,6 +110,8 @@ module API expose :star_count, :forks_count expose :last_activity_at + expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes + def self.preload_relation(projects_relation, options = {}) projects_relation.preload(:project_feature, :route) .preload(namespace: [:route, :owner], @@ -230,6 +233,8 @@ module API expose :parent_id end + expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes + expose :statistics, if: :statistics do with_options format_with: -> (value) { value.to_i } do expose :storage_size diff --git a/lib/api/groups.rb b/lib/api/groups.rb index b81f07a1770..4a4df1b8b9e 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -1,6 +1,7 @@ module API class Groups < Grape::API include PaginationParams + include Helpers::CustomAttributes before { authenticate_non_get! } @@ -67,6 +68,8 @@ module API } groups = groups.with_statistics if options[:statistics] + groups, options = with_custom_attributes(groups, options) + present paginate(groups), options end end @@ -79,6 +82,7 @@ module API end params do use :group_list_params + use :with_custom_attributes end get do groups = find_groups(params) @@ -142,9 +146,20 @@ module API desc 'Get a single group, with containing projects.' do success Entities::GroupDetail end + params do + use :with_custom_attributes + end get ":id" do group = find_group!(params[:id]) - present group, with: Entities::GroupDetail, current_user: current_user + + options = { + with: Entities::GroupDetail, + current_user: current_user + } + + group, options = with_custom_attributes(group, options) + + present group, options end desc 'Remove a group.' @@ -175,12 +190,19 @@ module API optional :starred, type: Boolean, default: false, desc: 'Limit by starred status' use :pagination + use :with_custom_attributes end get ":id/projects" do projects = find_group_projects(params) - entity = params[:simple] ? Entities::BasicProjectDetails : Entities::Project - present entity.prepare_relation(projects), with: entity, current_user: current_user + options = { + with: params[:simple] ? Entities::BasicProjectDetails : Entities::Project, + current_user: current_user + } + + projects, options = with_custom_attributes(projects, options) + + present options[:with].prepare_relation(projects), options end desc 'Get a list of subgroups in this group.' do @@ -188,6 +210,7 @@ module API end params do use :group_list_params + use :with_custom_attributes end get ":id/subgroups" do groups = find_groups(params) diff --git a/lib/api/helpers/custom_attributes.rb b/lib/api/helpers/custom_attributes.rb new file mode 100644 index 00000000000..70e4eda95f8 --- /dev/null +++ b/lib/api/helpers/custom_attributes.rb @@ -0,0 +1,28 @@ +module API + module Helpers + module CustomAttributes + extend ActiveSupport::Concern + + included do + helpers do + params :with_custom_attributes do + optional :with_custom_attributes, type: Boolean, default: false, desc: 'Include custom attributes in the response' + end + + def with_custom_attributes(collection_or_resource, options = {}) + options = options.merge( + with_custom_attributes: params[:with_custom_attributes] && + can?(current_user, :read_custom_attribute) + ) + + if options[:with_custom_attributes] && collection_or_resource.is_a?(ActiveRecord::Relation) + collection_or_resource = collection_or_resource.includes(:custom_attributes) + end + + [collection_or_resource, options] + end + end + end + end + end +end diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 5b481121a10..e90892a90f7 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -3,6 +3,7 @@ require_dependency 'declarative_policy' module API class Projects < Grape::API include PaginationParams + include Helpers::CustomAttributes before { authenticate_non_get! } @@ -80,6 +81,7 @@ module API projects = projects.with_merge_requests_enabled if params[:with_merge_requests_enabled] projects = projects.with_statistics if params[:statistics] projects = paginate(projects) + projects, options = with_custom_attributes(projects, options) if current_user project_members = current_user.project_members.preload(:source, user: [notification_settings: :source]) @@ -107,6 +109,7 @@ module API requires :user_id, type: String, desc: 'The ID or username of the user' use :collection_params use :statistics_params + use :with_custom_attributes end get ":user_id/projects" do user = find_user(params[:user_id]) @@ -127,6 +130,7 @@ module API params do use :collection_params use :statistics_params + use :with_custom_attributes end get do present_projects load_projects @@ -196,11 +200,19 @@ module API end params do use :statistics_params + use :with_custom_attributes end get ":id" do - entity = current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails - present user_project, with: entity, current_user: current_user, - user_can_admin_project: can?(current_user, :admin_project, user_project), statistics: params[:statistics] + options = { + with: current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails, + current_user: current_user, + user_can_admin_project: can?(current_user, :admin_project, user_project), + statistics: params[:statistics] + } + + project, options = with_custom_attributes(user_project, options) + + present project, options end desc 'Fork new project for the current user or provided namespace.' do @@ -242,6 +254,7 @@ module API end params do use :collection_params + use :with_custom_attributes end get ':id/forks' do forks = ForkProjectsFinder.new(user_project, params: project_finder_params, current_user: current_user).execute diff --git a/lib/api/users.rb b/lib/api/users.rb index 3cc12724b8a..3920171205f 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -2,6 +2,7 @@ module API class Users < Grape::API include PaginationParams include APIGuard + include Helpers::CustomAttributes allow_access_with_scope :read_user, if: -> (request) { request.get? } @@ -70,6 +71,7 @@ module API use :sort_params use :pagination + use :with_custom_attributes end get do authenticated_as_admin! if params[:external].present? || (params[:extern_uid].present? && params[:provider].present?) @@ -94,8 +96,9 @@ module API entity = current_user&.admin? ? Entities::UserWithAdmin : Entities::UserBasic users = users.preload(:identities, :u2f_registrations) if entity == Entities::UserWithAdmin + users, options = with_custom_attributes(users, with: entity) - present paginate(users), with: entity + present paginate(users), options end desc 'Get a single user' do @@ -103,12 +106,16 @@ module API end params do requires :id, type: Integer, desc: 'The ID of the user' + + use :with_custom_attributes end get ":id" do user = User.find_by(id: params[:id]) not_found!('User') unless user && can?(current_user, :read_user, user) opts = current_user&.admin? ? { with: Entities::UserWithAdmin } : { with: Entities::User } + user, opts = with_custom_attributes(user, opts) + present user, opts end -- cgit v1.2.1 From 8cdb3477b091e5c4ce08ef9f8caa65c7f5d925af Mon Sep 17 00:00:00 2001 From: Ahmad Sherif Date: Thu, 8 Feb 2018 17:14:45 +0100 Subject: Remove allow_n_plus_1 from Git::Repository#branches_filter --- lib/gitlab/git/repository.rb | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 6761fb0937a..5f014e43c6f 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -1614,17 +1614,14 @@ module Gitlab # Gitaly note: JV: Trying to get rid of the 'filter' option so we can implement this with 'git'. def branches_filter(filter: nil, sort_by: nil) - # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37464 - branches = Gitlab::GitalyClient.allow_n_plus_1_calls do - rugged.branches.each(filter).map do |rugged_ref| - begin - target_commit = Gitlab::Git::Commit.find(self, rugged_ref.target) - Gitlab::Git::Branch.new(self, rugged_ref.name, rugged_ref.target, target_commit) - rescue Rugged::ReferenceError - # Omit invalid branch - end - end.compact - end + branches = rugged.branches.each(filter).map do |rugged_ref| + begin + target_commit = Gitlab::Git::Commit.find(self, rugged_ref.target) + Gitlab::Git::Branch.new(self, rugged_ref.name, rugged_ref.target, target_commit) + rescue Rugged::ReferenceError + # Omit invalid branch + end + end.compact sort_branches(branches, sort_by) end -- cgit v1.2.1 From 4e72e4563c4425b39714f068e3f94f1a6f7ed26f Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 8 Feb 2018 23:07:28 -0600 Subject: Rename .scss files to use snake_case See https://gitlab.com/gitlab-org/gitlab-ce/issues/42908 --- lib/tasks/gemojione.rake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/tasks/gemojione.rake b/lib/tasks/gemojione.rake index c2d3a6b6950..c6942d22926 100644 --- a/lib/tasks/gemojione.rake +++ b/lib/tasks/gemojione.rake @@ -115,7 +115,7 @@ namespace :gemojione do end end - style_path = Rails.root.join(*%w(app assets stylesheets framework emoji-sprites.scss)) + style_path = Rails.root.join(*%w(app assets stylesheets framework emoji_sprites.scss)) # Combine the resized assets into a packed sprite and re-generate the SCSS SpriteFactory.cssurl = "image-url('$IMAGE')" -- cgit v1.2.1 From cea2a8f741d623ca2085e8149112de3a20a4779f Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Tue, 24 Oct 2017 13:28:06 +0300 Subject: Basic ref fetching for commits --- lib/api/commits.rb | 25 +++++++++++++++++++++++++ lib/api/entities.rb | 16 +++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index d8fd6a6eb06..3cf88551fa7 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -156,6 +156,31 @@ module API end end + desc 'Get all reference a commit is pushed to' do + detail 'This feature was introduced in GitLab 10.6' + success Entities::SimpleRef + end + params do + requires :sha, type: String, desc: 'A commit sha' + optional :type, type: String, values: %w(branches tags all), default: 'all', desc: 'Scope' + end + get ':id/repository/commits/:sha/refs', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do + commit = user_project.commit(params[:sha]) + not_found!('Commit') unless commit + + case params[:type] + when 'branches' + refs = user_project.repository.branch_names_contains(commit.id) + when 'tags' + refs = user_project.repository.tag_names_contains(commit.id) + else + refs = user_project.repository.branch_names_contains(commit.id) + refs.push(*user_project.repository.tag_names_contains(commit.id)) + end + + present refs, with: Entities::SimpleRef + end + desc 'Post comment to commit' do success Entities::CommitNote end diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 7838de13c56..e8c9ba6fce5 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -276,7 +276,17 @@ module API expose :last_pipeline, using: 'API::Entities::PipelineBasic' end - class Branch < Grape::Entity + class BasicRef < Grape::Entity + expose :name + end + + class SimpleRef < Grape::Entity + expose :name do |ref, options| + ref + end + end + + class Branch < BasicRef expose :name expose :commit, using: Entities::Commit do |repo_branch, options| @@ -845,8 +855,8 @@ module API expose :description end - class Tag < Grape::Entity - expose :name, :message + class Tag < BasicRef + expose :message expose :commit, using: Entities::Commit do |repo_tag, options| options[:project].repository.commit(repo_tag.dereferenced_target) -- cgit v1.2.1 From 4cefb568d96c4868404caa14534a4329e2dd887f Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 9 Feb 2018 14:30:27 +0100 Subject: Incorporate feedback --- lib/api/commits.rb | 29 +++++++++++++++-------------- lib/api/entities.rb | 10 +++------- 2 files changed, 18 insertions(+), 21 deletions(-) (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 3cf88551fa7..6d845253c3a 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -156,29 +156,30 @@ module API end end - desc 'Get all reference a commit is pushed to' do + desc 'Get all references a commit is pushed to' do detail 'This feature was introduced in GitLab 10.6' - success Entities::SimpleRef + success Entities::BasicRef end params do requires :sha, type: String, desc: 'A commit sha' - optional :type, type: String, values: %w(branches tags all), default: 'all', desc: 'Scope' + optional :type, type: String, values: %w[branches tags all], default: 'all', desc: 'Scope' end get ':id/repository/commits/:sha/refs', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do commit = user_project.commit(params[:sha]) not_found!('Commit') unless commit - case params[:type] - when 'branches' - refs = user_project.repository.branch_names_contains(commit.id) - when 'tags' - refs = user_project.repository.tag_names_contains(commit.id) - else - refs = user_project.repository.branch_names_contains(commit.id) - refs.push(*user_project.repository.tag_names_contains(commit.id)) - end + refs = + case params[:type] + when 'branches' + user_project.repository.branch_names_contains(commit.id) + when 'tags' + user_project.repository.tag_names_contains(commit.id) + else + refs = user_project.repository.branch_names_contains(commit.id) + refs.concat(user_project.repository.tag_names_contains(commit.id)) + end - present refs, with: Entities::SimpleRef + present refs, with: Entities::BasicRef end desc 'Post comment to commit' do @@ -190,7 +191,7 @@ module API optional :path, type: String, desc: 'The file path' given :path do requires :line, type: Integer, desc: 'The line number' - requires :line_type, type: String, values: %w(new old), default: 'new', desc: 'The type of the line' + requires :line_type, type: String, values: %w[new old], default: 'new', desc: 'The type of the line' end end post ':id/repository/commits/:sha/comments', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do diff --git a/lib/api/entities.rb b/lib/api/entities.rb index e8c9ba6fce5..054c04bbd98 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -277,16 +277,12 @@ module API end class BasicRef < Grape::Entity - expose :name - end - - class SimpleRef < Grape::Entity expose :name do |ref, options| ref end end - class Branch < BasicRef + class Branch < Grape::Entity expose :name expose :commit, using: Entities::Commit do |repo_branch, options| @@ -855,8 +851,8 @@ module API expose :description end - class Tag < BasicRef - expose :message + class Tag < Grape::Entity + expose :name, :message expose :commit, using: Entities::Commit do |repo_tag, options| options[:project].repository.commit(repo_tag.dereferenced_target) -- cgit v1.2.1 From 922d156a5e0412a12662df94e03479f7ed015f7b Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 9 Feb 2018 17:46:41 +0100 Subject: Separate branch and tag names --- lib/api/commits.rb | 8 ++++---- lib/api/entities.rb | 8 ++++++-- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 6d845253c3a..afaf68114e8 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -171,12 +171,12 @@ module API refs = case params[:type] when 'branches' - user_project.repository.branch_names_contains(commit.id) + user_project.repository.branch_names_contains(commit.id).map {|branch_name| [branch_name, true]} when 'tags' - user_project.repository.tag_names_contains(commit.id) + user_project.repository.tag_names_contains(commit.id).map {|tag_name| [tag_name, false]} else - refs = user_project.repository.branch_names_contains(commit.id) - refs.concat(user_project.repository.tag_names_contains(commit.id)) + refs = user_project.repository.branch_names_contains(commit.id).map {|branch_name| [branch_name, true]} + refs.concat(user_project.repository.tag_names_contains(commit.id).map {|tag_name| [tag_name, false]}) end present refs, with: Entities::BasicRef diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 054c04bbd98..c7a817877f0 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -277,8 +277,12 @@ module API end class BasicRef < Grape::Entity - expose :name do |ref, options| - ref + expose :branch_name, if: lambda { |ref, options| ref[1] } do |ref, options| + ref[0] + end + + expose :tag_name, if: lambda { |ref, options| !ref[1] } do |ref, options| + ref[0] end end -- cgit v1.2.1 From 68ff219c4ec9088005ab872e141912f35ecc59f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarka=20Kadlecov=C3=A1?= Date: Fri, 9 Feb 2018 15:38:52 +0100 Subject: API - fix searching in group/project specified by path --- lib/api/search.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/api/search.rb b/lib/api/search.rb index 9f08fd96a3b..b9982e03bb3 100644 --- a/lib/api/search.rb +++ b/lib/api/search.rb @@ -85,9 +85,9 @@ module API use :pagination end get ':id/-/search' do - find_group!(params[:id]) + group = find_group!(params[:id]) - present search(group_id: params[:id]), with: entity + present search(group_id: group.id), with: entity end end @@ -106,9 +106,9 @@ module API use :pagination end get ':id/-/search' do - find_project!(params[:id]) + project = find_project!(params[:id]) - present search(project_id: params[:id]), with: entity + present search(project_id: project.id), with: entity end end end -- cgit v1.2.1 From 603fa7c14193d37e3953225501d2108f0c581df5 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 31 Jan 2018 21:48:18 +0000 Subject: Merge branch 'fix-mermaid-xss' into 'security-10-4' [10.4] Fix stored XSS in code blocks --- lib/banzai/filter/syntax_highlight_filter.rb | 34 ++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb index a79a0154846..0ac7e231b5b 100644 --- a/lib/banzai/filter/syntax_highlight_filter.rb +++ b/lib/banzai/filter/syntax_highlight_filter.rb @@ -14,23 +14,33 @@ module Banzai end def highlight_node(node) - code = node.text css_classes = 'code highlight js-syntax-highlight' - language = node.attr('lang') + lang = node.attr('lang') + retried = false - if use_rouge?(language) - lexer = lexer_for(language) + if use_rouge?(lang) + lexer = lexer_for(lang) language = lexer.tag + else + lexer = Rouge::Lexers::PlainText.new + language = lang + end + + begin + code = Rouge::Formatters::HTMLGitlab.format(lex(lexer, node.text), tag: language) + css_classes << " #{language}" if language + rescue + # Gracefully handle syntax highlighter bugs/errors to ensure users can + # still access an issue/comment/etc. First, retry with the plain text + # filter. If that fails, then just skip this entirely, but that would + # be a pretty bad upstream bug. + return if retried - begin - code = Rouge::Formatters::HTMLGitlab.format(lex(lexer, code), tag: language) - css_classes << " #{language}" - rescue - # Gracefully handle syntax highlighter bugs/errors to ensure - # users can still access an issue/comment/etc. + language = nil + lexer = Rouge::Lexers::PlainText.new + retried = true - language = nil - end + retry end highlighted = %(
#{code}
) -- cgit v1.2.1 From fec9fb05a5775b864ef6768df166d39fcb2be4bc Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 18 Jan 2018 23:10:19 +0000 Subject: Merge branch 'security-10-4-todo-api-reveals-sensitive-information' into 'security-10-4' Restrict Todo API mark_as_done endpoint to the user's todos only --- lib/api/todos.rb | 2 +- lib/api/v3/todos.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/todos.rb b/lib/api/todos.rb index ffccfebe752..c6dbcf84e3a 100644 --- a/lib/api/todos.rb +++ b/lib/api/todos.rb @@ -60,7 +60,7 @@ module API end post ':id/mark_as_done' do TodoService.new.mark_todos_as_done_by_ids(params[:id], current_user) - todo = Todo.find(params[:id]) + todo = current_user.todos.find(params[:id]) present todo, with: Entities::Todo, current_user: current_user end diff --git a/lib/api/v3/todos.rb b/lib/api/v3/todos.rb index 2f2cf259987..3e2c61f6dbd 100644 --- a/lib/api/v3/todos.rb +++ b/lib/api/v3/todos.rb @@ -12,7 +12,7 @@ module API end delete ':id' do TodoService.new.mark_todos_as_done_by_ids(params[:id], current_user) - todo = Todo.find(params[:id]) + todo = current_user.todos.find(params[:id]) present todo, with: ::API::Entities::Todo, current_user: current_user end -- cgit v1.2.1 From 0d9107374a2caddea61351d2fd5ba619cb69df81 Mon Sep 17 00:00:00 2001 From: Ahmad Sherif Date: Fri, 9 Feb 2018 18:58:29 +0100 Subject: Return a warning string if we try to encode to unsupported encoding Fixes gitlab-development-kit#321 --- lib/gitlab/encoding_helper.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/encoding_helper.rb b/lib/gitlab/encoding_helper.rb index c0edcabc6fd..6659efa0961 100644 --- a/lib/gitlab/encoding_helper.rb +++ b/lib/gitlab/encoding_helper.rb @@ -28,9 +28,9 @@ module Gitlab # encode and clean the bad chars message.replace clean(message) - rescue ArgumentError - return nil - rescue + rescue ArgumentError => e + return unless e.message.include?('unknown encoding name') + encoding = detect ? detect[:encoding] : "unknown" "--broken encoding: #{encoding}" end -- cgit v1.2.1 From c6fa8c3fbaab2d7bcde5cecead129b085d5a2dae Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Mon, 12 Feb 2018 15:38:10 +0000 Subject: Create an empty wiki when there is no wiki in the gitlab export bundle --- lib/gitlab/import_export/importer.rb | 5 +++-- lib/gitlab/import_export/wiki_restorer.rb | 23 +++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 lib/gitlab/import_export/wiki_restorer.rb (limited to 'lib') diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb index c14646b0611..a00795f553e 100644 --- a/lib/gitlab/import_export/importer.rb +++ b/lib/gitlab/import_export/importer.rb @@ -50,9 +50,10 @@ module Gitlab end def wiki_restorer - Gitlab::ImportExport::RepoRestorer.new(path_to_bundle: wiki_repo_path, + Gitlab::ImportExport::WikiRestorer.new(path_to_bundle: wiki_repo_path, shared: @shared, - project: ProjectWiki.new(project_tree.restored_project)) + project: ProjectWiki.new(project_tree.restored_project), + wiki_enabled: @project.wiki_enabled?) end def uploads_restorer diff --git a/lib/gitlab/import_export/wiki_restorer.rb b/lib/gitlab/import_export/wiki_restorer.rb new file mode 100644 index 00000000000..f33bfb332ab --- /dev/null +++ b/lib/gitlab/import_export/wiki_restorer.rb @@ -0,0 +1,23 @@ +module Gitlab + module ImportExport + class WikiRestorer < RepoRestorer + def initialize(project:, shared:, path_to_bundle:, wiki_enabled:) + super(project: project, shared: shared, path_to_bundle: path_to_bundle) + + @wiki_enabled = wiki_enabled + end + + def restore + @project.wiki if create_empty_wiki? + + super + end + + private + + def create_empty_wiki? + !File.exist?(@path_to_bundle) && @wiki_enabled + end + end + end +end -- cgit v1.2.1 From 34c2a59c5794179d04c96a2df53a6ed3bd72d6b5 Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Mon, 12 Feb 2018 17:19:25 +0100 Subject: Honour workhorse provided file name In the attempt to unify file uploading at workhorse level gitlab-org/gitlab-workhorse!230 we moved to a prefix-based tempfile creation in order to avoid upload collisions. Artifacts and LFS uploads already set original_filename to workhorse provided filename This commit add the same feature to `Gitlab::Middleware::Multipart` --- lib/gitlab/middleware/multipart.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/middleware/multipart.rb b/lib/gitlab/middleware/multipart.rb index cc1e92480be..d4c54049b74 100644 --- a/lib/gitlab/middleware/multipart.rb +++ b/lib/gitlab/middleware/multipart.rb @@ -42,7 +42,7 @@ module Gitlab key, value = parsed_field.first if value.nil? - value = open_file(tmp_path) + value = open_file(tmp_path, @request.params["#{key}.name"]) @open_files << value else value = decorate_params_value(value, @request.params[key], tmp_path) @@ -70,7 +70,7 @@ module Gitlab case path_value when nil - value_hash[path_key] = open_file(tmp_path) + value_hash[path_key] = open_file(tmp_path, value_hash.dig(path_key, '.name')) @open_files << value_hash[path_key] value_hash when Hash @@ -81,8 +81,8 @@ module Gitlab end end - def open_file(path) - ::UploadedFile.new(path, File.basename(path), 'application/octet-stream') + def open_file(path, name) + ::UploadedFile.new(path, name || File.basename(path), 'application/octet-stream') end end -- cgit v1.2.1 From 740499bab5524d490218fd36033402cf67ec49f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Mon, 12 Feb 2018 12:39:47 -0500 Subject: Revert "Merge branch 'rd-40552-gitlab-should-check-if-keys-are-valid-before-saving' into 'master'" This reverts commit a58f8c32c62bcf5824d1fe1d0de53e9bda974d65, reversing changes made to cd5d75c362cdf06efb8174eddfbd0f4b65687dec. --- lib/gitlab/ssh_public_key.rb | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/ssh_public_key.rb b/lib/gitlab/ssh_public_key.rb index 545e7c74f7e..89ca1298120 100644 --- a/lib/gitlab/ssh_public_key.rb +++ b/lib/gitlab/ssh_public_key.rb @@ -21,22 +21,6 @@ module Gitlab technology(name)&.supported_sizes end - def self.sanitize(key_content) - ssh_type, *parts = key_content.strip.split - - return key_content if parts.empty? - - parts.each_with_object("#{ssh_type} ").with_index do |(part, content), index| - content << part - - if Gitlab::SSHPublicKey.new(content).valid? - break [content, parts[index + 1]].compact.join(' ') # Add the comment part if present - elsif parts.size == index + 1 # return original content if we've reached the last element - break key_content - end - end - end - attr_reader :key_text, :key # Unqualified MD5 fingerprint for compatibility @@ -53,23 +37,23 @@ module Gitlab end def valid? - key.present? && bits && technology.supported_sizes.include?(bits) + key.present? end def type - technology.name if key.present? + technology.name if valid? end def bits - return if key.blank? + return unless valid? case type when :rsa - key.n&.num_bits + key.n.num_bits when :dsa - key.p&.num_bits + key.p.num_bits when :ecdsa - key.group.order&.num_bits + key.group.order.num_bits when :ed25519 256 else -- cgit v1.2.1 From f917fc5d76d39fb17fda2678d5270407595f0128 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Thu, 8 Feb 2018 10:08:55 -0800 Subject: Fix last batch size equals max batch size error --- lib/gitlab/background_migration/prepare_untracked_uploads.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/background_migration/prepare_untracked_uploads.rb b/lib/gitlab/background_migration/prepare_untracked_uploads.rb index a7a1bbe1752..3aa4caf1841 100644 --- a/lib/gitlab/background_migration/prepare_untracked_uploads.rb +++ b/lib/gitlab/background_migration/prepare_untracked_uploads.rb @@ -92,7 +92,7 @@ module Gitlab end end - yield(paths) + yield(paths) if paths.any? end def build_find_command(search_dir) -- cgit v1.2.1 From 67d310a1a640088d497843ec8dce3f16eb285d2d Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Thu, 8 Feb 2018 10:17:00 -0800 Subject: Fix orphan temp table untracked_files_for_uploads --- lib/gitlab/background_migration/prepare_untracked_uploads.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/background_migration/prepare_untracked_uploads.rb b/lib/gitlab/background_migration/prepare_untracked_uploads.rb index 3aa4caf1841..298de005b9b 100644 --- a/lib/gitlab/background_migration/prepare_untracked_uploads.rb +++ b/lib/gitlab/background_migration/prepare_untracked_uploads.rb @@ -43,7 +43,11 @@ module Gitlab store_untracked_file_paths - schedule_populate_untracked_uploads_jobs + if UntrackedFile.all.empty? + drop_temp_table + else + schedule_populate_untracked_uploads_jobs + end end private @@ -165,6 +169,11 @@ module Gitlab bulk_queue_background_migration_jobs_by_range( UntrackedFile, FOLLOW_UP_MIGRATION) end + + def drop_temp_table + UntrackedFile.connection.drop_table(:untracked_files_for_uploads, + if_exists: true) + end end end end -- cgit v1.2.1 From 04b642889a0459ff38cca043c5898ba4647d2fc6 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 12 Feb 2018 11:15:26 -0800 Subject: Disable query limiting warnings for now on GitLab.com --- lib/gitlab/query_limiting.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/query_limiting.rb b/lib/gitlab/query_limiting.rb index f64f1757144..9f69a9e4a39 100644 --- a/lib/gitlab/query_limiting.rb +++ b/lib/gitlab/query_limiting.rb @@ -6,7 +6,7 @@ module Gitlab # This ensures we don't produce any errors that users can't do anything # about themselves. def self.enable? - Gitlab.com? || Rails.env.development? || Rails.env.test? + Rails.env.development? || Rails.env.test? end # Allows the current request to execute any number of SQL queries. -- cgit v1.2.1 From 06c111ca8f4373069ad0d3bbcf9e1ce2f5fd6d97 Mon Sep 17 00:00:00 2001 From: Dylan Griffith Date: Sun, 19 Nov 2017 14:01:01 +1100 Subject: Ensure users can't create environments with leading or trailing slashes (Fixes #39885) --- lib/gitlab/regex.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb index 7ab85e1c35c..ac3de2a8f71 100644 --- a/lib/gitlab/regex.rb +++ b/lib/gitlab/regex.rb @@ -40,12 +40,16 @@ module Gitlab 'a-zA-Z0-9_/\\$\\{\\}\\. \\-' end + def environment_name_regex_chars_without_slash + 'a-zA-Z0-9_\\$\\{\\}\\. -' + end + def environment_name_regex - @environment_name_regex ||= /\A[#{environment_name_regex_chars}]+\z/.freeze + @environment_name_regex ||= /\A[#{environment_name_regex_chars_without_slash}]([#{environment_name_regex_chars}]*[#{environment_name_regex_chars_without_slash}])?\z/.freeze end def environment_name_regex_message - "can contain only letters, digits, '-', '_', '/', '$', '{', '}', '.', and spaces" + "can contain only letters, digits, '-', '_', '/', '$', '{', '}', '.', and spaces, but it cannot start or end with '/'" end def kubernetes_namespace_regex -- cgit v1.2.1 From 848f49801d2c45227c525fb5ecdf8b71e7711ded Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 12 Feb 2018 12:40:55 +0100 Subject: add entity and update spec --- lib/api/api.rb | 1 + lib/api/entities.rb | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'lib') diff --git a/lib/api/api.rb b/lib/api/api.rb index e953f3d2eca..754549f72f0 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -138,6 +138,7 @@ module API mount ::API::PagesDomains mount ::API::Pipelines mount ::API::PipelineSchedules + mount ::API::ProjectImport mount ::API::ProjectHooks mount ::API::Projects mount ::API::ProjectMilestones diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 7838de13c56..8fbad2b6959 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -90,6 +90,11 @@ module API expose :created_at end + class ProjectImportStatus < ProjectIdentity + expose :import_status + expose :import_error, if: :import_error + end + class BasicProjectDetails < ProjectIdentity include ::API::ProjectsRelationBuilder -- cgit v1.2.1 From 82ff66ef31d6ff8ba2332f51b38f79b3bd7d64a5 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 12 Feb 2018 12:42:33 +0100 Subject: add post import API endpoint --- lib/api/project_import.rb | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 lib/api/project_import.rb (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb new file mode 100644 index 00000000000..4bbb78a62f9 --- /dev/null +++ b/lib/api/project_import.rb @@ -0,0 +1,48 @@ +module API + class ProjectImport < Grape::API + include PaginationParams + + helpers do + def import_params + declared_params(include_missing: false) + end + + def file_is_valid? + import_params[:file] && import_params[:file].respond_to?(:read) + end + end + + before do + not_found! unless Gitlab::CurrentSettings.import_sources.include?('gitlab_project') + end + + params do + optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' + requires :file, type: File, desc: 'The project export file to be imported' + end + resource :projects do + desc 'Get export status' do + success Entities::ProjectImportStatus + end + post 'import' do + render_api_error!('The branch refname is invalid', 400) unless file_is_valid? + + namespace = import_params[:namespace] + + namespace = if namespace && namespace =~ /^\d+$/ + Namespace.find_by(id: namespace) + elsif namespace.blank? + current_user.namespace + else + Namespace.find_by_path_or_name(namespace) + end + + project = ::Projects::GitlabProjectsImportService.new(current_user, import_params).execute + + render_api_error!(link.project.full_messages.first, 400) unless project.saved? + + present project, with: Entities::ProjectImportStatus + end + end + end +end -- cgit v1.2.1 From d3b3f5d1b4def5e87f90a2347acc0b0ee8edc80a Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 12 Feb 2018 14:46:47 +0100 Subject: update import API and spec --- lib/api/project_import.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index 4bbb78a62f9..396c316af22 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -17,6 +17,7 @@ module API end params do + requires :name, type: String, desc: 'The new project name' optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' requires :file, type: File, desc: 'The project export file to be imported' end @@ -37,9 +38,11 @@ module API Namespace.find_by_path_or_name(namespace) end - project = ::Projects::GitlabProjectsImportService.new(current_user, import_params).execute + project_params = import_params.merge(namespace: namespace.id) - render_api_error!(link.project.full_messages.first, 400) unless project.saved? + project = ::Projects::GitlabProjectsImportService.new(current_user, project_params).execute + + render_api_error!(project.full_messages.first, 400) unless project.saved? present project, with: Entities::ProjectImportStatus end -- cgit v1.2.1 From 516d33f5ac8f65d8d69d1e5e88efbf0faabbe0eb Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 12 Feb 2018 15:26:59 +0100 Subject: update import API and spec --- lib/api/project_import.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index 396c316af22..1b63f4d4d9f 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -17,7 +17,7 @@ module API end params do - requires :name, type: String, desc: 'The new project name' + requires :path, type: String, desc: 'The new project path and name' optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' requires :file, type: File, desc: 'The project export file to be imported' end @@ -38,7 +38,7 @@ module API Namespace.find_by_path_or_name(namespace) end - project_params = import_params.merge(namespace: namespace.id) + project_params = import_params.merge(namespace_id: namespace.id) project = ::Projects::GitlabProjectsImportService.new(current_user, project_params).execute -- cgit v1.2.1 From 7ec1a022b79c68dd3232c0abf07d119f0dad808f Mon Sep 17 00:00:00 2001 From: James Lopez Date: Mon, 12 Feb 2018 16:02:15 +0100 Subject: fix file upload --- lib/api/project_import.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index 1b63f4d4d9f..5a4e4189a58 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -8,7 +8,7 @@ module API end def file_is_valid? - import_params[:file] && import_params[:file].respond_to?(:read) + import_params[:file] && import_params[:file]['tempfile'].respond_to?(:read) end end @@ -26,7 +26,7 @@ module API success Entities::ProjectImportStatus end post 'import' do - render_api_error!('The branch refname is invalid', 400) unless file_is_valid? + render_api_error!('The file is invalid', 400) unless file_is_valid? namespace = import_params[:namespace] @@ -38,7 +38,8 @@ module API Namespace.find_by_path_or_name(namespace) end - project_params = import_params.merge(namespace_id: namespace.id) + project_params = import_params.merge(namespace_id: namespace.id, + file: import_params[:file]['tempfile']) project = ::Projects::GitlabProjectsImportService.new(current_user, project_params).execute -- cgit v1.2.1 From 583ed0eb94ff938b4986491e27af5f3c97ea6baf Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 13 Feb 2018 09:24:10 +0100 Subject: add import status endpoint --- lib/api/project_import.rb | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index 5a4e4189a58..d554d6d12bd 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -16,12 +16,13 @@ module API not_found! unless Gitlab::CurrentSettings.import_sources.include?('gitlab_project') end - params do - requires :path, type: String, desc: 'The new project path and name' - optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' - requires :file, type: File, desc: 'The project export file to be imported' - end - resource :projects do + resource :projects, requirements: { id: %r{[^/]+} } do + + params do + requires :path, type: String, desc: 'The new project path and name' + optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' + requires :file, type: File, desc: 'The project export file to be imported' + end desc 'Get export status' do success Entities::ProjectImportStatus end @@ -40,13 +41,22 @@ module API project_params = import_params.merge(namespace_id: namespace.id, file: import_params[:file]['tempfile']) - project = ::Projects::GitlabProjectsImportService.new(current_user, project_params).execute - render_api_error!(project.full_messages.first, 400) unless project.saved? + render_api_error!(project&.full_messages&.first, 400) unless project&.saved? present project, with: Entities::ProjectImportStatus end + + params do + requires :id, type: String, desc: 'The ID of a project' + end + desc 'Get export status' do + success Entities::ProjectImportStatus + end + get ':id/import' do + present user_project, with: Entities::ProjectImportStatus + end end end end -- cgit v1.2.1 From 4a0d56daacc3f1825c5f9644a0ea63842fa9da7d Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 13 Feb 2018 09:47:47 +0100 Subject: fix entity --- lib/api/entities.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 8fbad2b6959..ffdb06b8094 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -92,7 +92,9 @@ module API class ProjectImportStatus < ProjectIdentity expose :import_status - expose :import_error, if: :import_error + + # TODO: Use `expose_nil` once we upgrade the grape-entity gem + expose :import_error, if: lambda { |status, _ops| status.import_error } end class BasicProjectDetails < ProjectIdentity -- cgit v1.2.1 From 79879145e5cfb3837b3a2f77fb7c35bd1234068c Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 13 Feb 2018 10:54:04 +0100 Subject: add more specs --- lib/api/project_import.rb | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index d554d6d12bd..1e51c92cbf1 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -17,7 +17,6 @@ module API end resource :projects, requirements: { id: %r{[^/]+} } do - params do requires :path, type: String, desc: 'The new project path and name' optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' @@ -30,11 +29,10 @@ module API render_api_error!('The file is invalid', 400) unless file_is_valid? namespace = import_params[:namespace] - - namespace = if namespace && namespace =~ /^\d+$/ - Namespace.find_by(id: namespace) - elsif namespace.blank? + namespace = if namespace.blank? current_user.namespace + elsif namespace =~ /^\d+$/ + Namespace.find_by(id: namespace) else Namespace.find_by_path_or_name(namespace) end @@ -43,7 +41,7 @@ module API file: import_params[:file]['tempfile']) project = ::Projects::GitlabProjectsImportService.new(current_user, project_params).execute - render_api_error!(project&.full_messages&.first, 400) unless project&.saved? + render_api_error!(project.errors.full_messages&.first, 400) unless project.saved? present project, with: Entities::ProjectImportStatus end -- cgit v1.2.1 From 17e5ef4b269f4c13d22bd5c10086c6226dc43543 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 13 Feb 2018 15:04:19 +0100 Subject: add docs and changelog --- lib/api/project_import.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index 1e51c92cbf1..e93c14ddcf5 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -19,8 +19,8 @@ module API resource :projects, requirements: { id: %r{[^/]+} } do params do requires :path, type: String, desc: 'The new project path and name' - optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' requires :file, type: File, desc: 'The project export file to be imported' + optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' end desc 'Get export status' do success Entities::ProjectImportStatus -- cgit v1.2.1 From e8813520029f0f07b0cf2d8463337ae09f15b7fe Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 13 Feb 2018 15:18:52 +0100 Subject: refactor api class --- lib/api/project_import.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index e93c14ddcf5..b0511342b63 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -13,7 +13,7 @@ module API end before do - not_found! unless Gitlab::CurrentSettings.import_sources.include?('gitlab_project') + forbidden! unless Gitlab::CurrentSettings.import_sources.include?('gitlab_project') end resource :projects, requirements: { id: %r{[^/]+} } do @@ -22,12 +22,14 @@ module API requires :file, type: File, desc: 'The project export file to be imported' optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' end - desc 'Get export status' do + desc 'Create a new project import' do success Entities::ProjectImportStatus end post 'import' do render_api_error!('The file is invalid', 400) unless file_is_valid? + Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42437') + namespace = import_params[:namespace] namespace = if namespace.blank? current_user.namespace @@ -49,7 +51,7 @@ module API params do requires :id, type: String, desc: 'The ID of a project' end - desc 'Get export status' do + desc 'Get a project export status' do success Entities::ProjectImportStatus end get ':id/import' do -- cgit v1.2.1 From b45c7dd5fecd33d1fbc9053cb353d7ed0c6d57dd Mon Sep 17 00:00:00 2001 From: Drew Blessing Date: Thu, 25 Jan 2018 16:18:15 -0600 Subject: Revert problematic LDAP person validation that threw exceptions Constructors shouldn't throw exceptions. We also learned that different LDAP servers behave a bit unexpectedly sometimes - returning attributes we didn't ask for, or returned attributes with language subtypes. --- lib/gitlab/ldap/person.rb | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb index e81cec6ba1a..ec41f0ea090 100644 --- a/lib/gitlab/ldap/person.rb +++ b/lib/gitlab/ldap/person.rb @@ -63,8 +63,6 @@ module Gitlab Rails.logger.debug { "Instantiating #{self.class.name} with LDIF:\n#{entry.to_ldif}" } @entry = entry @provider = provider - - validate_entry end def name @@ -115,19 +113,6 @@ module Gitlab entry.public_send(selected_attr) # rubocop:disable GitlabSecurity/PublicSend end - - def validate_entry - allowed_attrs = self.class.ldap_attributes(config).map(&:downcase) - - # Net::LDAP::Entry transforms keys to symbols. Change to strings to compare. - entry_attrs = entry.attribute_names.map { |n| n.to_s.downcase } - invalid_attrs = entry_attrs - allowed_attrs - - if invalid_attrs.any? - raise InvalidEntryError, - "#{self.class.name} initialized with Net::LDAP::Entry containing invalid attributes(s): #{invalid_attrs}" - end - end end end end -- cgit v1.2.1 From e3bd674e81d565ef3bd399a70b3039316b518693 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 13 Feb 2018 16:40:23 +0100 Subject: Remove Sentry reporting for query limiting Using Sentry, while useful, poses two problems you have to choose from: 1. All errors are reported separately, making it easy to create issues but also making it next to impossible to see other errors (due to the sheer volume of threshold errors). 2. Errors can be grouped or merged together, reducing the noise. This however also means it's (as far as I can tell) much harder to automatically create GitLab issues from Sentry for the offending controllers. Since both solutions are terrible I decided to go with a third option: not using Sentry for this at all. Instead we'll investigate using Prometheus alerts and Grafana dashboards for this, which has the added benefit of being able to more accurately measure the behaviour over time. Note that throwing errors in test environments is still enabled, and whitelisting is still necessary to prevent that from happening (and that in turn still requires that developers create issues). --- lib/gitlab/query_limiting/transaction.rb | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/query_limiting/transaction.rb b/lib/gitlab/query_limiting/transaction.rb index 3cbafadb0d0..66d7d9275cf 100644 --- a/lib/gitlab/query_limiting/transaction.rb +++ b/lib/gitlab/query_limiting/transaction.rb @@ -51,13 +51,7 @@ module Gitlab error = ThresholdExceededError.new(error_message) - if raise_error? - raise(error) - else - # Raven automatically logs to the Rails log if disabled, thus we don't - # need to manually log anything in case Sentry support is not enabled. - Raven.capture_exception(error) - end + raise(error) if raise_error? end def increment -- cgit v1.2.1 From b0b4ae1875529cd7ca786bd5eccd49be9a40a038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarka=20Kadlecov=C3=A1?= Date: Tue, 13 Feb 2018 13:41:35 +0100 Subject: API - Include project in commits&blobs search results --- lib/api/entities.rb | 2 ++ lib/api/search.rb | 12 ++++-------- lib/gitlab/file_finder.rb | 5 +++-- lib/gitlab/project_search_results.rb | 5 +++-- lib/gitlab/search_results.rb | 3 ++- 5 files changed, 14 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 7838de13c56..1608af97d38 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -274,6 +274,7 @@ module API expose :stats, using: Entities::CommitStats, if: :stats expose :status expose :last_pipeline, using: 'API::Entities::PipelineBasic' + expose :project_id end class Branch < Grape::Entity @@ -1172,6 +1173,7 @@ module API expose :id expose :ref expose :startline + expose :project_id end end end diff --git a/lib/api/search.rb b/lib/api/search.rb index b9982e03bb3..3556ad98c52 100644 --- a/lib/api/search.rb +++ b/lib/api/search.rb @@ -11,7 +11,7 @@ module API projects: Entities::BasicProjectDetails, milestones: Entities::Milestone, notes: Entities::Note, - commits: Entities::Commit, + commits: Entities::CommitDetail, blobs: Entities::Blob, wiki_blobs: Entities::Blob, snippet_titles: Entities::Snippet, @@ -35,7 +35,7 @@ module API def process_results(results) case params[:scope] when 'wiki_blobs' - paginate(results).map { |blob| Gitlab::ProjectSearchResults.parse_search_result(blob) } + paginate(results).map { |blob| Gitlab::ProjectSearchResults.parse_search_result(blob, user_project) } when 'blobs' paginate(results).map { |blob| blob[1] } else @@ -85,9 +85,7 @@ module API use :pagination end get ':id/-/search' do - group = find_group!(params[:id]) - - present search(group_id: group.id), with: entity + present search(group_id: user_group.id), with: entity end end @@ -106,9 +104,7 @@ module API use :pagination end get ':id/-/search' do - project = find_project!(params[:id]) - - present search(project_id: project.id), with: entity + present search(project_id: user_project.id), with: entity end end end diff --git a/lib/gitlab/file_finder.rb b/lib/gitlab/file_finder.rb index 10ffc345bd5..8c082c0c336 100644 --- a/lib/gitlab/file_finder.rb +++ b/lib/gitlab/file_finder.rb @@ -28,7 +28,7 @@ module Gitlab def find_by_content(query) results = repository.search_files_by_content(query, ref).first(BATCH_SIZE) - results.map { |result| Gitlab::ProjectSearchResults.parse_search_result(result) } + results.map { |result| Gitlab::ProjectSearchResults.parse_search_result(result, project) } end def find_by_filename(query, except: []) @@ -45,7 +45,8 @@ module Gitlab basename: File.basename(blob.path), ref: ref, startline: 1, - data: blob.data + data: blob.data, + project: project ) end end diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index 9e2fa07a205..cf0935dbd9a 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -41,7 +41,7 @@ module Gitlab @commits_count ||= commits.count end - def self.parse_search_result(result) + def self.parse_search_result(result, project = nil) ref = nil filename = nil basename = nil @@ -66,7 +66,8 @@ module Gitlab basename: basename, ref: ref, startline: startline, - data: data + data: data, + project_id: project ? project.id : nil ) end diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb index 5ad219179f3..5a5ae7f19d4 100644 --- a/lib/gitlab/search_results.rb +++ b/lib/gitlab/search_results.rb @@ -1,7 +1,7 @@ module Gitlab class SearchResults class FoundBlob - attr_reader :id, :filename, :basename, :ref, :startline, :data + attr_reader :id, :filename, :basename, :ref, :startline, :data, :project_id def initialize(opts = {}) @id = opts.fetch(:id, nil) @@ -11,6 +11,7 @@ module Gitlab @startline = opts.fetch(:startline, nil) @data = opts.fetch(:data, nil) @per_page = opts.fetch(:per_page, 20) + @project_id = opts.fetch(:project_id, nil) end def path -- cgit v1.2.1 From a724f7e35f9f8ed9692b0f3f4d6c8a62632cdec4 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Tue, 13 Feb 2018 20:22:37 +0100 Subject: Refactor commits/refs API to use hash and add pagination headers --- lib/api/commits.rb | 19 +++++++------------ lib/api/entities.rb | 8 +------- 2 files changed, 8 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index afaf68114e8..d83c43ee49b 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -162,24 +162,19 @@ module API end params do requires :sha, type: String, desc: 'A commit sha' - optional :type, type: String, values: %w[branches tags all], default: 'all', desc: 'Scope' + optional :type, type: String, values: %w[branch tag all], default: 'all', desc: 'Scope' + use :pagination end get ':id/repository/commits/:sha/refs', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do commit = user_project.commit(params[:sha]) not_found!('Commit') unless commit - refs = - case params[:type] - when 'branches' - user_project.repository.branch_names_contains(commit.id).map {|branch_name| [branch_name, true]} - when 'tags' - user_project.repository.tag_names_contains(commit.id).map {|tag_name| [tag_name, false]} - else - refs = user_project.repository.branch_names_contains(commit.id).map {|branch_name| [branch_name, true]} - refs.concat(user_project.repository.tag_names_contains(commit.id).map {|tag_name| [tag_name, false]}) - end + refs = [] + refs.concat(user_project.repository.branch_names_contains(commit.id).map {|name| { type: 'branch', name: name }}) unless params[:type] == 'tag' + refs.concat(user_project.repository.tag_names_contains(commit.id).map {|name| { type: 'tag', name: name }}) unless params[:type] == 'branch' + refs = Kaminari.paginate_array(refs) - present refs, with: Entities::BasicRef + present paginate(refs), with: Entities::BasicRef end desc 'Post comment to commit' do diff --git a/lib/api/entities.rb b/lib/api/entities.rb index c7a817877f0..c8cda85b170 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -277,13 +277,7 @@ module API end class BasicRef < Grape::Entity - expose :branch_name, if: lambda { |ref, options| ref[1] } do |ref, options| - ref[0] - end - - expose :tag_name, if: lambda { |ref, options| !ref[1] } do |ref, options| - ref[0] - end + expose :type, :name end class Branch < Grape::Entity -- cgit v1.2.1 From 84e7654c1afe9d42c1d96a4b79d49e450d8373eb Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Wed, 14 Feb 2018 13:27:29 +0200 Subject: Remove Gitlab::ImportExport::ProjectCreator class --- lib/gitlab/import_export/project_creator.rb | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 lib/gitlab/import_export/project_creator.rb (limited to 'lib') diff --git a/lib/gitlab/import_export/project_creator.rb b/lib/gitlab/import_export/project_creator.rb deleted file mode 100644 index 77bb3ca6581..00000000000 --- a/lib/gitlab/import_export/project_creator.rb +++ /dev/null @@ -1,23 +0,0 @@ -module Gitlab - module ImportExport - class ProjectCreator - def initialize(namespace_id, current_user, file, project_path) - @namespace_id = namespace_id - @current_user = current_user - @file = file - @project_path = project_path - end - - def execute - ::Projects::CreateService.new( - @current_user, - name: @project_path, - path: @project_path, - namespace_id: @namespace_id, - import_type: "gitlab_project", - import_source: @file - ).execute - end - end - end -end -- cgit v1.2.1 From 080dba4a7e036e4bcb9cae69c5de6bfa33ff8b2e Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Tue, 13 Feb 2018 12:31:30 -0800 Subject: Avoid dropping tables in test And use :migration tag to use deletion strategy, and to avoid caching tables, and to lock into a particular schema. Attempting to fix intermittent spec errors `PG::UndefinedTable: ERROR: relation "public.untracked_files_for_uploads" does not exist`. --- lib/gitlab/background_migration/populate_untracked_uploads.rb | 2 +- lib/gitlab/background_migration/prepare_untracked_uploads.rb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/background_migration/populate_untracked_uploads.rb b/lib/gitlab/background_migration/populate_untracked_uploads.rb index 8a8e770940e..ee55fabd6f0 100644 --- a/lib/gitlab/background_migration/populate_untracked_uploads.rb +++ b/lib/gitlab/background_migration/populate_untracked_uploads.rb @@ -249,7 +249,7 @@ module Gitlab end def drop_temp_table_if_finished - if UntrackedFile.all.empty? + if UntrackedFile.all.empty? && !Rails.env.test? # Dropping a table intermittently breaks test cleanup UntrackedFile.connection.drop_table(:untracked_files_for_uploads, if_exists: true) end diff --git a/lib/gitlab/background_migration/prepare_untracked_uploads.rb b/lib/gitlab/background_migration/prepare_untracked_uploads.rb index 298de005b9b..914a9e48a2f 100644 --- a/lib/gitlab/background_migration/prepare_untracked_uploads.rb +++ b/lib/gitlab/background_migration/prepare_untracked_uploads.rb @@ -171,8 +171,10 @@ module Gitlab end def drop_temp_table - UntrackedFile.connection.drop_table(:untracked_files_for_uploads, - if_exists: true) + unless Rails.env.test? # Dropping a table intermittently breaks test cleanup + UntrackedFile.connection.drop_table(:untracked_files_for_uploads, + if_exists: true) + end end end end -- cgit v1.2.1 From e613d777b258a4f7070d2b7aaee093901e4b7ed7 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 14 Feb 2018 14:46:40 +0100 Subject: refactor code based on feedback --- lib/api/project_import.rb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index b0511342b63..88fe1d2b5f5 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -10,19 +10,24 @@ module API def file_is_valid? import_params[:file] && import_params[:file]['tempfile'].respond_to?(:read) end + + def validate_file! + render_api_error!('The file is invalid', 400) unless file_is_valid? + end end before do forbidden! unless Gitlab::CurrentSettings.import_sources.include?('gitlab_project') end - resource :projects, requirements: { id: %r{[^/]+} } do + resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do params do requires :path, type: String, desc: 'The new project path and name' requires :file, type: File, desc: 'The project export file to be imported' optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' end desc 'Create a new project import' do + detail 'This feature was introduced in GitLab 10.6.' success Entities::ProjectImportStatus end post 'import' do @@ -30,13 +35,10 @@ module API Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42437') - namespace = import_params[:namespace] - namespace = if namespace.blank? - current_user.namespace - elsif namespace =~ /^\d+$/ - Namespace.find_by(id: namespace) + namespace = if import_params[:namespace] + find_namespace!(import_params[:namespace]) else - Namespace.find_by_path_or_name(namespace) + current_user.namespace end project_params = import_params.merge(namespace_id: namespace.id, @@ -52,6 +54,7 @@ module API requires :id, type: String, desc: 'The ID of a project' end desc 'Get a project export status' do + detail 'This feature was introduced in GitLab 10.6.' success Entities::ProjectImportStatus end get ':id/import' do -- cgit v1.2.1 From 0abd85f919053efa8a03add9ae43ce9ea2d02ae5 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 14 Feb 2018 14:59:11 +0100 Subject: refactor code based on feedback --- lib/api/project_import.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index 88fe1d2b5f5..a6da9b90fe3 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -31,7 +31,7 @@ module API success Entities::ProjectImportStatus end post 'import' do - render_api_error!('The file is invalid', 400) unless file_is_valid? + validate_file! Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42437') -- cgit v1.2.1 From e4990b66df64f2e23502d161f411335c9a771a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 26 Jan 2018 15:23:46 +0100 Subject: Combine all rake tasks in the static-analysis job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/tasks/lint.rake | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'lib') diff --git a/lib/tasks/lint.rake b/lib/tasks/lint.rake index 3ab406eff2c..e7812ff3568 100644 --- a/lib/tasks/lint.rake +++ b/lib/tasks/lint.rake @@ -16,5 +16,33 @@ unless Rails.env.production? task :javascript do Rake::Task['eslint'].invoke end + + desc "GitLab | lint | Run several lint checks" + task :all do + status = 0 + original_stdout = $stdout + + %w[ + config_lint + haml_lint + scss_lint + flay + gettext:lint + lint:static_verification + ].each do |task| + begin + $stdout = StringIO.new + Rake::Task[task].invoke + rescue RuntimeError, SystemExit => ex + raise ex if ex.is_a?(RuntimeError) && task != 'haml_lint' + original_stdout << $stdout.string + status = 1 + ensure + $stdout = original_stdout + end + end + + exit status + end end end -- cgit v1.2.1 From 2f0d2ab55b6deac79f81834f6724a676ceae94ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 12 Feb 2018 18:34:07 +0100 Subject: Run lint:all tasks in forks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/tasks/lint.rake | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/tasks/lint.rake b/lib/tasks/lint.rake index e7812ff3568..fe5032cae18 100644 --- a/lib/tasks/lint.rake +++ b/lib/tasks/lint.rake @@ -20,7 +20,6 @@ unless Rails.env.production? desc "GitLab | lint | Run several lint checks" task :all do status = 0 - original_stdout = $stdout %w[ config_lint @@ -30,19 +29,41 @@ unless Rails.env.production? gettext:lint lint:static_verification ].each do |task| - begin - $stdout = StringIO.new - Rake::Task[task].invoke - rescue RuntimeError, SystemExit => ex - raise ex if ex.is_a?(RuntimeError) && task != 'haml_lint' - original_stdout << $stdout.string - status = 1 - ensure - $stdout = original_stdout + pid = Process.fork do + rd, wr = IO.pipe + stdout = $stdout.dup + stderr = $stderr.dup + $stdout.reopen(wr) + $stderr.reopen(wr) + + begin + begin + Rake::Task[task].invoke + rescue RuntimeError # The haml_lint tasks raise a RuntimeError + exit(1) + end + rescue SystemExit => ex + msg = "*** Rake task #{task} failed with the following error(s):" + raise ex + ensure + $stdout.reopen(stdout) + $stderr.reopen(stderr) + wr.close + + if msg + warn "\n#{msg}\n\n" + IO.copy_stream(rd, $stderr) + else + IO.copy_stream(rd, $stdout) + end + end end + + Process.waitpid(pid) + status += $?.exitstatus end - exit status + exit(status) end end end -- cgit v1.2.1 From 9a450aedc2c81f8ce17e4c9b4238c58edbef8269 Mon Sep 17 00:00:00 2001 From: Turo Soisenniemi Date: Wed, 14 Feb 2018 19:41:13 +0000 Subject: Set Asciidoctor outfilesuffix to default .adoc Without setting outfilesuffix Asciidoctor defaults to .html. When .html is used, inter-document cross references do not work in Gitlab's repository / file renderer. See more information from http://asciidoctor.org/docs/user-manual/#navigating-between-source-files and http://asciidoctor.org/docs/user-manual/#inter-document-cross-references --- lib/gitlab/asciidoc.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb index ee7f4be6b9f..62c41801d75 100644 --- a/lib/gitlab/asciidoc.rb +++ b/lib/gitlab/asciidoc.rb @@ -8,7 +8,8 @@ module Gitlab module Asciidoc DEFAULT_ADOC_ATTRS = [ 'showtitle', 'idprefix=user-content-', 'idseparator=-', 'env=gitlab', - 'env-gitlab', 'source-highlighter=html-pipeline', 'icons=font' + 'env-gitlab', 'source-highlighter=html-pipeline', 'icons=font', + 'outfilesuffix=.adoc' ].freeze # Public: Converts the provided Asciidoc markup into HTML. -- cgit v1.2.1 From c88fe70f90c885b0568cdf68e467d5b26bbb142b Mon Sep 17 00:00:00 2001 From: James Edwards-Jones Date: Tue, 13 Feb 2018 19:33:13 +0000 Subject: Only check LFS integrity for first branch in push --- lib/gitlab/checks/change_access.rb | 7 ++++--- lib/gitlab/git_access.rb | 9 ++++++--- lib/gitlab/git_access_wiki.rb | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb index d75e73dac10..521680b8708 100644 --- a/lib/gitlab/checks/change_access.rb +++ b/lib/gitlab/checks/change_access.rb @@ -16,11 +16,11 @@ module Gitlab lfs_objects_missing: 'LFS objects are missing. Ensure LFS is properly set up or try a manual "git lfs push --all".' }.freeze - attr_reader :user_access, :project, :skip_authorization, :protocol, :oldrev, :newrev, :ref, :branch_name, :tag_name + attr_reader :user_access, :project, :skip_authorization, :skip_lfs_integrity_check, :protocol, :oldrev, :newrev, :ref, :branch_name, :tag_name def initialize( change, user_access:, project:, skip_authorization: false, - protocol: + skip_lfs_integrity_check: false, protocol: ) @oldrev, @newrev, @ref = change.values_at(:oldrev, :newrev, :ref) @branch_name = Gitlab::Git.branch_name(@ref) @@ -28,6 +28,7 @@ module Gitlab @user_access = user_access @project = project @skip_authorization = skip_authorization + @skip_lfs_integrity_check = skip_lfs_integrity_check @protocol = protocol end @@ -37,7 +38,7 @@ module Gitlab push_checks branch_checks tag_checks - lfs_objects_exist_check + lfs_objects_exist_check unless skip_lfs_integrity_check commits_check unless skip_commits_check true diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 8ec3386184a..9ec3858b493 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -238,19 +238,22 @@ module Gitlab changes_list = Gitlab::ChangesList.new(changes) # Iterate over all changes to find if user allowed all of them to be applied - changes_list.each do |change| + changes_list.each.with_index do |change, index| + first_change = index == 0 + # If user does not have access to make at least one change, cancel all # push by allowing the exception to bubble up - check_single_change_access(change) + check_single_change_access(change, skip_lfs_integrity_check: !first_change) end end - def check_single_change_access(change) + def check_single_change_access(change, skip_lfs_integrity_check: false) Checks::ChangeAccess.new( change, user_access: user_access, project: project, skip_authorization: deploy_key?, + skip_lfs_integrity_check: skip_lfs_integrity_check, protocol: protocol ).exec end diff --git a/lib/gitlab/git_access_wiki.rb b/lib/gitlab/git_access_wiki.rb index 1c9477e84b2..84d6e1490c3 100644 --- a/lib/gitlab/git_access_wiki.rb +++ b/lib/gitlab/git_access_wiki.rb @@ -13,7 +13,7 @@ module Gitlab authentication_abilities.include?(:download_code) && user_access.can_do_action?(:download_wiki_code) end - def check_single_change_access(change) + def check_single_change_access(change, _options = {}) unless user_access.can_do_action?(:create_wiki) raise UnauthorizedError, ERROR_MESSAGES[:write_to_wiki] end -- cgit v1.2.1 From 26af0e2d601401114a0574203a56f5f71417adf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?= Date: Thu, 15 Feb 2018 09:27:38 +0000 Subject: Fixed user synced attributes metadata after removing current provider --- lib/gitlab/ldap/config.rb | 2 +- lib/gitlab/o_auth/user.rb | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb index 47b3fce3e7a..a6bea98d631 100644 --- a/lib/gitlab/ldap/config.rb +++ b/lib/gitlab/ldap/config.rb @@ -15,7 +15,7 @@ module Gitlab end def self.servers - Gitlab.config.ldap.servers.values + Gitlab.config.ldap['servers']&.values || [] end def self.available_servers diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb index a3e1c66c19f..ed5ab7b174d 100644 --- a/lib/gitlab/o_auth/user.rb +++ b/lib/gitlab/o_auth/user.rb @@ -198,9 +198,11 @@ module Gitlab end def update_profile + clear_user_synced_attributes_metadata + return unless sync_profile_from_provider? || creating_linked_ldap_user? - metadata = gl_user.user_synced_attributes_metadata || gl_user.build_user_synced_attributes_metadata + metadata = gl_user.build_user_synced_attributes_metadata if sync_profile_from_provider? UserSyncedAttributesMetadata::SYNCABLE_ATTRIBUTES.each do |key| @@ -221,6 +223,10 @@ module Gitlab end end + def clear_user_synced_attributes_metadata + gl_user.user_synced_attributes_metadata&.destroy + end + def log Gitlab::AppLogger end -- cgit v1.2.1 From bed60b8c47acd11569da7cf5dc5bdb545ac97784 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 15 Feb 2018 12:06:57 +0100 Subject: Escape HTML entities in commit messages --- lib/banzai/filter/html_entity_filter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/banzai/filter/html_entity_filter.rb b/lib/banzai/filter/html_entity_filter.rb index f3bd587c28b..e008fd428b0 100644 --- a/lib/banzai/filter/html_entity_filter.rb +++ b/lib/banzai/filter/html_entity_filter.rb @@ -5,7 +5,7 @@ module Banzai # Text filter that escapes these HTML entities: & " < > class HtmlEntityFilter < HTML::Pipeline::TextFilter def call - ERB::Util.html_escape_once(text) + ERB::Util.html_escape(text) end end end -- cgit v1.2.1 From 75fd83245450216b0aeec9993455802764eaf87b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Thu, 15 Feb 2018 09:50:19 -0500 Subject: Revert "Merge branch 'rd-43185-revert-sanitize-extra-blank-spaces-used-when-uploading-a-ssh-key' into 'master'" This reverts commit e607fd796657afd214b8f25201919d3e33b3f35f. --- lib/gitlab/ssh_public_key.rb | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/ssh_public_key.rb b/lib/gitlab/ssh_public_key.rb index 89ca1298120..545e7c74f7e 100644 --- a/lib/gitlab/ssh_public_key.rb +++ b/lib/gitlab/ssh_public_key.rb @@ -21,6 +21,22 @@ module Gitlab technology(name)&.supported_sizes end + def self.sanitize(key_content) + ssh_type, *parts = key_content.strip.split + + return key_content if parts.empty? + + parts.each_with_object("#{ssh_type} ").with_index do |(part, content), index| + content << part + + if Gitlab::SSHPublicKey.new(content).valid? + break [content, parts[index + 1]].compact.join(' ') # Add the comment part if present + elsif parts.size == index + 1 # return original content if we've reached the last element + break key_content + end + end + end + attr_reader :key_text, :key # Unqualified MD5 fingerprint for compatibility @@ -37,23 +53,23 @@ module Gitlab end def valid? - key.present? + key.present? && bits && technology.supported_sizes.include?(bits) end def type - technology.name if valid? + technology.name if key.present? end def bits - return unless valid? + return if key.blank? case type when :rsa - key.n.num_bits + key.n&.num_bits when :dsa - key.p.num_bits + key.p&.num_bits when :ecdsa - key.group.order.num_bits + key.group.order&.num_bits when :ed25519 256 else -- cgit v1.2.1 From a7ac45809f1f3ccaa1a2b124f2532d8684931c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?= Date: Thu, 15 Feb 2018 17:18:17 +0100 Subject: Fixed bug with the user synced attributes when the user doesn't exist --- lib/gitlab/o_auth/user.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb index ed5ab7b174d..28ebac1776e 100644 --- a/lib/gitlab/o_auth/user.rb +++ b/lib/gitlab/o_auth/user.rb @@ -224,7 +224,7 @@ module Gitlab end def clear_user_synced_attributes_metadata - gl_user.user_synced_attributes_metadata&.destroy + gl_user&.user_synced_attributes_metadata&.destroy end def log -- cgit v1.2.1 From bda4f0811e3d7f3530d1d6c338e2de6ada5bf1f2 Mon Sep 17 00:00:00 2001 From: Dylan Griffith Date: Fri, 16 Feb 2018 17:38:45 +1100 Subject: Improve error handling for Gitlab::Profiler and improve doc about providing a user --- lib/gitlab/profiler.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/gitlab/profiler.rb b/lib/gitlab/profiler.rb index 95d94b3cc68..98a168b43bb 100644 --- a/lib/gitlab/profiler.rb +++ b/lib/gitlab/profiler.rb @@ -45,6 +45,7 @@ module Gitlab if user private_token ||= user.personal_access_tokens.active.pluck(:token).first + raise 'Your user must have a personal_access_token' unless private_token end headers['Private-Token'] = private_token if private_token -- cgit v1.2.1 From 890d7b540b1ffbadcde490a2e1b741bbb1af3cf4 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 16 Feb 2018 14:37:26 +0100 Subject: update docs --- lib/api/project_import.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index a6da9b90fe3..c32e2f26ae3 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -24,7 +24,7 @@ module API params do requires :path, type: String, desc: 'The new project path and name' requires :file, type: File, desc: 'The project export file to be imported' - optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be imported into. Defaults to the user namespace.' + optional :namespace, type: String, desc: "The ID or name of the namespace that the project will be imported into. Defaults to the current user's namespace." end desc 'Create a new project import' do detail 'This feature was introduced in GitLab 10.6.' -- cgit v1.2.1 From 7044a3a54a4ee4dd45af111727df2ff512db1a22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Fri, 16 Feb 2018 11:32:08 -0500 Subject: Validate SSH keys through the sshkey gem --- lib/gitlab/ssh_public_key.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/ssh_public_key.rb b/lib/gitlab/ssh_public_key.rb index 545e7c74f7e..6f63ea91ae8 100644 --- a/lib/gitlab/ssh_public_key.rb +++ b/lib/gitlab/ssh_public_key.rb @@ -53,7 +53,7 @@ module Gitlab end def valid? - key.present? && bits && technology.supported_sizes.include?(bits) + SSHKey.valid_ssh_public_key?(key_text) end def type -- cgit v1.2.1 From d8dfec0ffa4fdbb383bf4f0d1ef71969adb50dd3 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Fri, 16 Feb 2018 18:03:34 +0100 Subject: Fix project import API after import service refactor --- lib/api/project_import.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb index c32e2f26ae3..a509c1f32c1 100644 --- a/lib/api/project_import.rb +++ b/lib/api/project_import.rb @@ -41,8 +41,12 @@ module API current_user.namespace end - project_params = import_params.merge(namespace_id: namespace.id, - file: import_params[:file]['tempfile']) + project_params = { + path: import_params[:path], + namespace_id: namespace.id, + file: import_params[:file]['tempfile'] + } + project = ::Projects::GitlabProjectsImportService.new(current_user, project_params).execute render_api_error!(project.errors.full_messages&.first, 400) unless project.saved? -- cgit v1.2.1 From f9492554617d807b35358cb799d26e3422dd4c71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mica=C3=ABl=20Bergeron?= Date: Mon, 12 Feb 2018 09:02:15 -0500 Subject: fix specs --- lib/gitlab/git/commit.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index d95561fe1b2..28a8a79e36e 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -471,6 +471,14 @@ module Gitlab private + def parent_ids=(shas) + @parent_ids = case shas + when String then JSON.parse(shas) + else + shas + end + end + def init_from_hash(hash) raw_commit = hash.symbolize_keys -- cgit v1.2.1 From af5cd10e00402937310dfe8e4dfa48b0c15b157a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mica=C3=ABl=20Bergeron?= Date: Fri, 16 Feb 2018 13:49:07 -0500 Subject: applying feedback # modified: lib/gitlab/git/commit.rb --- lib/gitlab/git/commit.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index 28a8a79e36e..ea59978c58a 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -473,7 +473,8 @@ module Gitlab def parent_ids=(shas) @parent_ids = case shas - when String then JSON.parse(shas) + when String + JSON.parse(shas) else shas end -- cgit v1.2.1 From 348c60d9be8b0e358d766c46e3e6d343af3e187a Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Thu, 15 Feb 2018 13:20:55 -0800 Subject: Remove codebase dependencies from a BG migration Specifically, `PopulateUntrackedUploads` and its spec. --- .../populate_untracked_uploads.rb | 11 ++-- .../populate_untracked_uploads_dependencies.rb | 59 ++++++++++++++++++++++ 2 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 lib/gitlab/background_migration/populate_untracked_uploads_dependencies.rb (limited to 'lib') diff --git a/lib/gitlab/background_migration/populate_untracked_uploads.rb b/lib/gitlab/background_migration/populate_untracked_uploads.rb index ee55fabd6f0..c0aa64e27ed 100644 --- a/lib/gitlab/background_migration/populate_untracked_uploads.rb +++ b/lib/gitlab/background_migration/populate_untracked_uploads.rb @@ -5,11 +5,15 @@ module Gitlab # This class processes a batch of rows in `untracked_files_for_uploads` by # adding each file to the `uploads` table if it does not exist. class PopulateUntrackedUploads # rubocop:disable Metrics/ClassLength + include PopulateUntrackedUploadsDependencies + # This class is responsible for producing the attributes necessary to # track an uploaded file in the `uploads` table. class UntrackedFile < ActiveRecord::Base # rubocop:disable Metrics/ClassLength, Metrics/LineLength self.table_name = 'untracked_files_for_uploads' + include PopulateUntrackedUploadsDependencies + # Ends with /:random_hex/:filename FILE_UPLOADER_PATH = %r{/\h+/[^/]+\z} FULL_PATH_CAPTURE = /\A(.+)#{FILE_UPLOADER_PATH}/ @@ -147,11 +151,6 @@ module Gitlab end end - # This class is used to query the `uploads` table. - class Upload < ActiveRecord::Base - self.table_name = 'uploads' - end - def perform(start_id, end_id) return unless migrate? @@ -229,7 +228,7 @@ module Gitlab end ids.each do |model_type, model_ids| - model_class = Object.const_get(model_type) + model_class = self.class.const_get(model_type) found_ids = model_class.where(id: model_ids.uniq).pluck(:id) deleted_ids = ids[model_type] - found_ids ids[model_type] = deleted_ids diff --git a/lib/gitlab/background_migration/populate_untracked_uploads_dependencies.rb b/lib/gitlab/background_migration/populate_untracked_uploads_dependencies.rb new file mode 100644 index 00000000000..188aeed4fbf --- /dev/null +++ b/lib/gitlab/background_migration/populate_untracked_uploads_dependencies.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true +module Gitlab + module BackgroundMigration + module PopulateUntrackedUploadsDependencies + # Avoid using application code + class Upload < ActiveRecord::Base + self.table_name = 'uploads' + end + + # Avoid using application code + class Appearance < ActiveRecord::Base + self.table_name = 'appearances' + end + + # Avoid using application code + class Namespace < ActiveRecord::Base + self.table_name = 'namespaces' + end + + # Avoid using application code + class Note < ActiveRecord::Base + self.table_name = 'notes' + end + + # Avoid using application code + class User < ActiveRecord::Base + self.table_name = 'users' + end + + # Since project Markdown upload paths don't contain the project ID, we have to find the + # project by its full_path. Due to MySQL/PostgreSQL differences, and historical reasons, + # the logic is somewhat complex, so I've mostly copied it in here. + class Project < ActiveRecord::Base + self.table_name = 'projects' + + def self.find_by_full_path(path) + binary = Gitlab::Database.mysql? ? 'BINARY' : '' + order_sql = "(CASE WHEN #{binary} routes.path = #{connection.quote(path)} THEN 0 ELSE 1 END)" + where_full_path_in(path).reorder(order_sql).take + end + + def self.where_full_path_in(path) + cast_lower = Gitlab::Database.postgresql? + + path = connection.quote(path) + + where = + if cast_lower + "(LOWER(routes.path) = LOWER(#{path}))" + else + "(routes.path = #{path})" + end + + joins("INNER JOIN routes ON routes.source_id = projects.id AND routes.source_type = 'Project'").where(where) + end + end + end + end +end -- cgit v1.2.1 From 8d32dfef9b7eefe3d48dc63398315ba41879329c Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 18 Feb 2018 21:45:51 -0800 Subject: Fix squash rebase not working when diff contained encoded data When the applied diff contains UTF-8 or some other encoded data, the diff returned back from the git process may be in ASCII-8BIT format. Writing this data to stdin may fail if the data because stdin expects this data to be in UTF-8. By switching the output to binmode, we ensure that the diff will always be written as-is. Closes gitlab-org/gitlab-ee#4960 --- lib/gitlab/git/repository.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 5f014e43c6f..a10bc0dd32b 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -2195,6 +2195,7 @@ module Gitlab # Apply diff of the `diff_range` to the worktree diff = run_git!(%W(diff --binary #{diff_range})) run_git!(%w(apply --index), chdir: squash_path, env: env) do |stdin| + stdin.binmode stdin.write(diff) end -- cgit v1.2.1 From 15ca2d5fb5961399d8031fa3c9da818ffb9cbb0f Mon Sep 17 00:00:00 2001 From: Travis Miller Date: Mon, 19 Feb 2018 00:02:13 -0600 Subject: Fix get a single pages domain when project path contains a period --- lib/api/pages_domains.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/api/pages_domains.rb b/lib/api/pages_domains.rb index d7b613a717e..ba33993d852 100644 --- a/lib/api/pages_domains.rb +++ b/lib/api/pages_domains.rb @@ -2,6 +2,8 @@ module API class PagesDomains < Grape::API include PaginationParams + PAGES_DOMAINS_ENDPOINT_REQUIREMENTS = API::PROJECT_ENDPOINT_REQUIREMENTS.merge(domain: API::NO_SLASH_URL_PART_REGEX) + before do authenticate! end @@ -48,7 +50,7 @@ module API params do requires :id, type: String, desc: 'The ID of a project' end - resource :projects, requirements: { id: %r{[^/]+} } do + resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do before do require_pages_enabled! end @@ -71,7 +73,7 @@ module API params do requires :domain, type: String, desc: 'The domain' end - get ":id/pages/domains/:domain", requirements: { domain: %r{[^/]+} } do + get ":id/pages/domains/:domain", requirements: PAGES_DOMAINS_ENDPOINT_REQUIREMENTS do authorize! :read_pages, user_project present pages_domain, with: Entities::PagesDomain @@ -105,7 +107,7 @@ module API optional :certificate, allow_blank: false, types: [File, String], desc: 'The certificate' optional :key, allow_blank: false, types: [File, String], desc: 'The key' end - put ":id/pages/domains/:domain", requirements: { domain: %r{[^/]+} } do + put ":id/pages/domains/:domain", requirements: PAGES_DOMAINS_ENDPOINT_REQUIREMENTS do authorize! :update_pages, user_project pages_domain_params = declared(params, include_parent_namespaces: false) @@ -126,7 +128,7 @@ module API params do requires :domain, type: String, desc: 'The domain' end - delete ":id/pages/domains/:domain", requirements: { domain: %r{[^/]+} } do + delete ":id/pages/domains/:domain", requirements: PAGES_DOMAINS_ENDPOINT_REQUIREMENTS do authorize! :update_pages, user_project status 204 -- cgit v1.2.1 From fdad576838c16d0ae7d181e85a5889d8ae4e5014 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 19 Feb 2018 00:21:47 -0800 Subject: Fix Error 500 when viewing a commit with a GPG signature in Geo Closes gitlab-org/gitlab-ee#4825 --- lib/gitlab/gpg/commit.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/gpg/commit.rb b/lib/gitlab/gpg/commit.rb index 672b5579dfd..90dd569aaf8 100644 --- a/lib/gitlab/gpg/commit.rb +++ b/lib/gitlab/gpg/commit.rb @@ -60,7 +60,9 @@ module Gitlab def create_cached_signature! using_keychain do |gpg_key| - GpgSignature.create!(attributes(gpg_key)) + signature = GpgSignature.new(attributes(gpg_key)) + signature.save! unless Gitlab::Database.read_only? + signature end end -- cgit v1.2.1 From d4dfa342c1f5a916d325e198ff19d3f702bfb3d9 Mon Sep 17 00:00:00 2001 From: James Edwards-Jones Date: Thu, 15 Feb 2018 05:21:17 +0000 Subject: Avoid slow File Lock checks when not used Also avoid double commit lookup during file lock check by reusing memoized commits. --- lib/gitlab/checks/change_access.rb | 7 ++++++- lib/gitlab/checks/commit_check.rb | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb index d75e73dac10..94d45c17ca0 100644 --- a/lib/gitlab/checks/change_access.rb +++ b/lib/gitlab/checks/change_access.rb @@ -120,6 +120,7 @@ module Gitlab def commits_check return if deletion? || newrev.nil? + return unless should_run_commit_validations? # n+1: https://gitlab.com/gitlab-org/gitlab-ee/issues/3593 ::Gitlab::GitalyClient.allow_n_plus_1_calls do @@ -138,6 +139,10 @@ module Gitlab private + def should_run_commit_validations? + commit_check.validate_lfs_file_locks? + end + def updated_from_web? protocol == 'web' end @@ -175,7 +180,7 @@ module Gitlab end def commits - project.repository.new_commits(newrev) + @commits ||= project.repository.new_commits(newrev) end end end diff --git a/lib/gitlab/checks/commit_check.rb b/lib/gitlab/checks/commit_check.rb index ae0cd142378..43a52b493bb 100644 --- a/lib/gitlab/checks/commit_check.rb +++ b/lib/gitlab/checks/commit_check.rb @@ -35,14 +35,14 @@ module Gitlab end end - private - def validate_lfs_file_locks? strong_memoize(:validate_lfs_file_locks) do project.lfs_enabled? && project.lfs_file_locks.any? && newrev && oldrev end end + private + def lfs_file_locks_validation lambda do |paths| lfs_lock = project.lfs_file_locks.where(path: paths).where.not(user_id: user.id).first -- cgit v1.2.1 From 23dd313d76f2254a7a5c58283cb76236a160647b Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Mon, 19 Feb 2018 11:21:23 +0000 Subject: Convert Gitaly commit parent IDs to array as early as possible The tracking issue if this causes problems is https://gitlab.com/gitlab-org/gitaly/issues/1028 --- lib/gitlab/git/commit.rb | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb index ea59978c58a..ae27a138b7c 100644 --- a/lib/gitlab/git/commit.rb +++ b/lib/gitlab/git/commit.rb @@ -471,15 +471,6 @@ module Gitlab private - def parent_ids=(shas) - @parent_ids = case shas - when String - JSON.parse(shas) - else - shas - end - end - def init_from_hash(hash) raw_commit = hash.symbolize_keys @@ -517,7 +508,7 @@ module Gitlab @committed_date = Time.at(commit.committer.date.seconds).utc @committer_name = commit.committer.name.dup @committer_email = commit.committer.email.dup - @parent_ids = commit.parent_ids + @parent_ids = Array(commit.parent_ids) end def serialize_keys -- cgit v1.2.1 From 01f5035bfe2c2fa6cc71564e8a02fbcb325e3370 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Mon, 19 Feb 2018 15:11:10 +0000 Subject: Fix squash with renamed files We need to ignore the names for renamed files when configuring with sparse checkout. --- lib/gitlab/git/repository.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index a10bc0dd32b..4261f028d35 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -2188,7 +2188,7 @@ module Gitlab ) diff_range = "#{start_sha}...#{end_sha}" diff_files = run_git!( - %W(diff --name-only --diff-filter=a --binary #{diff_range}) + %W(diff --name-only --diff-filter=ar --binary #{diff_range}) ).chomp with_worktree(squash_path, branch, sparse_checkout_files: diff_files, env: env) do -- cgit v1.2.1 From 69b750aee9f51f1206495531e14c1f9b6d421600 Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Mon, 19 Feb 2018 17:56:33 +0000 Subject: [GH Import] Create an empty wiki if wiki import failed --- lib/gitlab/github_import/importer/repository_importer.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/gitlab/github_import/importer/repository_importer.rb b/lib/gitlab/github_import/importer/repository_importer.rb index 7dd68a0d1cd..ab0b751fe24 100644 --- a/lib/gitlab/github_import/importer/repository_importer.rb +++ b/lib/gitlab/github_import/importer/repository_importer.rb @@ -63,6 +63,7 @@ module Gitlab true rescue Gitlab::Shell::Error => e if e.message !~ /repository not exported/ + project.create_wiki fail_import("Failed to import the wiki: #{e.message}") else true -- cgit v1.2.1 From 0dafea8685f0376d4c474f7670a97d0b8e449767 Mon Sep 17 00:00:00 2001 From: Maxime Roussin-Belanger Date: Sun, 18 Feb 2018 22:17:23 -0500 Subject: Add missing pagination on the commit diff endpoint --- lib/api/commits.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/api/commits.rb b/lib/api/commits.rb index d83c43ee49b..3d6e78d2d80 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -97,13 +97,16 @@ module API end params do requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag' + use :pagination end get ':id/repository/commits/:sha/diff', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do commit = user_project.commit(params[:sha]) not_found! 'Commit' unless commit - present commit.raw_diffs.to_a, with: Entities::Diff + raw_diffs = ::Kaminari.paginate_array(commit.raw_diffs.to_a) + + present paginate(raw_diffs), with: Entities::Diff end desc "Get a commit's comments" do -- cgit v1.2.1 From 93c0a168ab0c47075c8589c8506e4438ca9a0484 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 20 Feb 2018 13:25:17 +0100 Subject: Put all event metrics exposed to prometheus behind a feature flag --- lib/gitlab/metrics/transaction.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb index 45b9e14ba55..e6e66cf92d3 100644 --- a/lib/gitlab/metrics/transaction.rb +++ b/lib/gitlab/metrics/transaction.rb @@ -155,6 +155,7 @@ module Gitlab fetch_metric(type, metric_name) do docstring "Transaction #{prefix}#{name} #{type}" base_labels tags.merge(BASE_LABELS) + with_feature "prometheus_transaction_#{prefix}#{name}_total".to_sym if type == :gauge multiprocess_mode :livesum -- cgit v1.2.1 From 50c9ba43f80e1da16532162984c2ebcecdcbbd48 Mon Sep 17 00:00:00 2001 From: Pawel Chojnacki Date: Tue, 20 Feb 2018 14:06:12 +0100 Subject: Only use features for events --- lib/gitlab/metrics/transaction.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb index e6e66cf92d3..f3e48083c19 100644 --- a/lib/gitlab/metrics/transaction.rb +++ b/lib/gitlab/metrics/transaction.rb @@ -73,7 +73,7 @@ module Gitlab # event_name - The name of the event (e.g. "git_push"). # tags - A set of tags to attach to the event. def add_event(event_name, tags = {}) - self.class.transaction_metric(event_name, :counter, prefix: 'event_', tags: tags).increment(tags.merge(labels)) + self.class.transaction_metric(event_name, :counter, prefix: 'event_', use_feature_flag: true, tags: tags).increment(tags.merge(labels)) @metrics << Metric.new(EVENT_SERIES, { count: 1 }, tags.merge(event: event_name), :event) end @@ -150,12 +150,12 @@ module Gitlab with_feature :prometheus_metrics_transaction_allocated_memory end - def self.transaction_metric(name, type, prefix: nil, tags: {}) + def self.transaction_metric(name, type, prefix: nil, use_feature_flag: false, tags: {}) metric_name = "gitlab_transaction_#{prefix}#{name}_total".to_sym fetch_metric(type, metric_name) do docstring "Transaction #{prefix}#{name} #{type}" base_labels tags.merge(BASE_LABELS) - with_feature "prometheus_transaction_#{prefix}#{name}_total".to_sym + with_feature "prometheus_transaction_#{prefix}#{name}_total".to_sym if use_feature_flag if type == :gauge multiprocess_mode :livesum -- cgit v1.2.1 From 4b49eb495debdbe6f808fd38904dbae0055fda0e Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Tue, 20 Feb 2018 11:37:46 -0800 Subject: Explicitly reference redefined models And move UntrackedFile into PopulateUntrackedUploadsDependencies, and move its spec into its own file. --- .../populate_untracked_uploads.rb | 159 +-------------------- .../populate_untracked_uploads_dependencies.rb | 142 ++++++++++++++++++ 2 files changed, 149 insertions(+), 152 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/background_migration/populate_untracked_uploads.rb b/lib/gitlab/background_migration/populate_untracked_uploads.rb index c0aa64e27ed..c5415bf0f9a 100644 --- a/lib/gitlab/background_migration/populate_untracked_uploads.rb +++ b/lib/gitlab/background_migration/populate_untracked_uploads.rb @@ -5,156 +5,10 @@ module Gitlab # This class processes a batch of rows in `untracked_files_for_uploads` by # adding each file to the `uploads` table if it does not exist. class PopulateUntrackedUploads # rubocop:disable Metrics/ClassLength - include PopulateUntrackedUploadsDependencies - - # This class is responsible for producing the attributes necessary to - # track an uploaded file in the `uploads` table. - class UntrackedFile < ActiveRecord::Base # rubocop:disable Metrics/ClassLength, Metrics/LineLength - self.table_name = 'untracked_files_for_uploads' - - include PopulateUntrackedUploadsDependencies - - # Ends with /:random_hex/:filename - FILE_UPLOADER_PATH = %r{/\h+/[^/]+\z} - FULL_PATH_CAPTURE = /\A(.+)#{FILE_UPLOADER_PATH}/ - - # These regex patterns are tested against a relative path, relative to - # the upload directory. - # For convenience, if there exists a capture group in the pattern, then - # it indicates the model_id. - PATH_PATTERNS = [ - { - pattern: %r{\A-/system/appearance/logo/(\d+)/}, - uploader: 'AttachmentUploader', - model_type: 'Appearance' - }, - { - pattern: %r{\A-/system/appearance/header_logo/(\d+)/}, - uploader: 'AttachmentUploader', - model_type: 'Appearance' - }, - { - pattern: %r{\A-/system/note/attachment/(\d+)/}, - uploader: 'AttachmentUploader', - model_type: 'Note' - }, - { - pattern: %r{\A-/system/user/avatar/(\d+)/}, - uploader: 'AvatarUploader', - model_type: 'User' - }, - { - pattern: %r{\A-/system/group/avatar/(\d+)/}, - uploader: 'AvatarUploader', - model_type: 'Namespace' - }, - { - pattern: %r{\A-/system/project/avatar/(\d+)/}, - uploader: 'AvatarUploader', - model_type: 'Project' - }, - { - pattern: FILE_UPLOADER_PATH, - uploader: 'FileUploader', - model_type: 'Project' - } - ].freeze - - def to_h - @upload_hash ||= { - path: upload_path, - uploader: uploader, - model_type: model_type, - model_id: model_id, - size: file_size, - checksum: checksum - } - end - - def upload_path - # UntrackedFile#path is absolute, but Upload#path depends on uploader - @upload_path ||= - if uploader == 'FileUploader' - # Path relative to project directory in uploads - matchd = path_relative_to_upload_dir.match(FILE_UPLOADER_PATH) - matchd[0].sub(%r{\A/}, '') # remove leading slash - else - path - end - end - - def uploader - matching_pattern_map[:uploader] - end - - def model_type - matching_pattern_map[:model_type] - end - - def model_id - return @model_id if defined?(@model_id) - - pattern = matching_pattern_map[:pattern] - matchd = path_relative_to_upload_dir.match(pattern) - - # If something is captured (matchd[1] is not nil), it is a model_id - # Only the FileUploader pattern will not match an ID - @model_id = matchd[1] ? matchd[1].to_i : file_uploader_model_id - end - - def file_size - File.size(absolute_path) - end - - def checksum - Digest::SHA256.file(absolute_path).hexdigest - end - - private - - def matching_pattern_map - @matching_pattern_map ||= PATH_PATTERNS.find do |path_pattern_map| - path_relative_to_upload_dir.match(path_pattern_map[:pattern]) - end - - unless @matching_pattern_map - raise "Unknown upload path pattern \"#{path}\"" - end - - @matching_pattern_map - end - - def file_uploader_model_id - matchd = path_relative_to_upload_dir.match(FULL_PATH_CAPTURE) - not_found_msg = <<~MSG - Could not capture project full_path from a FileUploader path: - "#{path_relative_to_upload_dir}" - MSG - raise not_found_msg unless matchd - - full_path = matchd[1] - project = Project.find_by_full_path(full_path) - return nil unless project - - project.id - end - - # Not including a leading slash - def path_relative_to_upload_dir - upload_dir = Gitlab::BackgroundMigration::PrepareUntrackedUploads::RELATIVE_UPLOAD_DIR # rubocop:disable Metrics/LineLength - base = %r{\A#{Regexp.escape(upload_dir)}/} - @path_relative_to_upload_dir ||= path.sub(base, '') - end - - def absolute_path - File.join(Gitlab.config.uploads.storage_path, path) - end - end - def perform(start_id, end_id) return unless migrate? - files = UntrackedFile.where(id: start_id..end_id) + files = Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::UntrackedFile.where(id: start_id..end_id) processed_files = insert_uploads_if_needed(files) processed_files.delete_all @@ -164,7 +18,8 @@ module Gitlab private def migrate? - UntrackedFile.table_exists? && Upload.table_exists? + Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::UntrackedFile.table_exists? && + Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::Upload.table_exists? end def insert_uploads_if_needed(files) @@ -196,7 +51,7 @@ module Gitlab def filter_existing_uploads(files) paths = files.map(&:upload_path) - existing_paths = Upload.where(path: paths).pluck(:path).to_set + existing_paths = Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::Upload.where(path: paths).pluck(:path).to_set files.reject do |file| existing_paths.include?(file.upload_path) @@ -228,7 +83,7 @@ module Gitlab end ids.each do |model_type, model_ids| - model_class = self.class.const_get(model_type) + model_class = Object.const_get("Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::#{model_type}") found_ids = model_class.where(id: model_ids.uniq).pluck(:id) deleted_ids = ids[model_type] - found_ids ids[model_type] = deleted_ids @@ -248,8 +103,8 @@ module Gitlab end def drop_temp_table_if_finished - if UntrackedFile.all.empty? && !Rails.env.test? # Dropping a table intermittently breaks test cleanup - UntrackedFile.connection.drop_table(:untracked_files_for_uploads, + if Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::UntrackedFile.all.empty? && !Rails.env.test? # Dropping a table intermittently breaks test cleanup + Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::UntrackedFile.connection.drop_table(:untracked_files_for_uploads, if_exists: true) end end diff --git a/lib/gitlab/background_migration/populate_untracked_uploads_dependencies.rb b/lib/gitlab/background_migration/populate_untracked_uploads_dependencies.rb index 188aeed4fbf..a2c5acbde71 100644 --- a/lib/gitlab/background_migration/populate_untracked_uploads_dependencies.rb +++ b/lib/gitlab/background_migration/populate_untracked_uploads_dependencies.rb @@ -2,6 +2,148 @@ module Gitlab module BackgroundMigration module PopulateUntrackedUploadsDependencies + # This class is responsible for producing the attributes necessary to + # track an uploaded file in the `uploads` table. + class UntrackedFile < ActiveRecord::Base # rubocop:disable Metrics/ClassLength, Metrics/LineLength + self.table_name = 'untracked_files_for_uploads' + + # Ends with /:random_hex/:filename + FILE_UPLOADER_PATH = %r{/\h+/[^/]+\z} + FULL_PATH_CAPTURE = /\A(.+)#{FILE_UPLOADER_PATH}/ + + # These regex patterns are tested against a relative path, relative to + # the upload directory. + # For convenience, if there exists a capture group in the pattern, then + # it indicates the model_id. + PATH_PATTERNS = [ + { + pattern: %r{\A-/system/appearance/logo/(\d+)/}, + uploader: 'AttachmentUploader', + model_type: 'Appearance' + }, + { + pattern: %r{\A-/system/appearance/header_logo/(\d+)/}, + uploader: 'AttachmentUploader', + model_type: 'Appearance' + }, + { + pattern: %r{\A-/system/note/attachment/(\d+)/}, + uploader: 'AttachmentUploader', + model_type: 'Note' + }, + { + pattern: %r{\A-/system/user/avatar/(\d+)/}, + uploader: 'AvatarUploader', + model_type: 'User' + }, + { + pattern: %r{\A-/system/group/avatar/(\d+)/}, + uploader: 'AvatarUploader', + model_type: 'Namespace' + }, + { + pattern: %r{\A-/system/project/avatar/(\d+)/}, + uploader: 'AvatarUploader', + model_type: 'Project' + }, + { + pattern: FILE_UPLOADER_PATH, + uploader: 'FileUploader', + model_type: 'Project' + } + ].freeze + + def to_h + @upload_hash ||= { + path: upload_path, + uploader: uploader, + model_type: model_type, + model_id: model_id, + size: file_size, + checksum: checksum + } + end + + def upload_path + # UntrackedFile#path is absolute, but Upload#path depends on uploader + @upload_path ||= + if uploader == 'FileUploader' + # Path relative to project directory in uploads + matchd = path_relative_to_upload_dir.match(FILE_UPLOADER_PATH) + matchd[0].sub(%r{\A/}, '') # remove leading slash + else + path + end + end + + def uploader + matching_pattern_map[:uploader] + end + + def model_type + matching_pattern_map[:model_type] + end + + def model_id + return @model_id if defined?(@model_id) + + pattern = matching_pattern_map[:pattern] + matchd = path_relative_to_upload_dir.match(pattern) + + # If something is captured (matchd[1] is not nil), it is a model_id + # Only the FileUploader pattern will not match an ID + @model_id = matchd[1] ? matchd[1].to_i : file_uploader_model_id + end + + def file_size + File.size(absolute_path) + end + + def checksum + Digest::SHA256.file(absolute_path).hexdigest + end + + private + + def matching_pattern_map + @matching_pattern_map ||= PATH_PATTERNS.find do |path_pattern_map| + path_relative_to_upload_dir.match(path_pattern_map[:pattern]) + end + + unless @matching_pattern_map + raise "Unknown upload path pattern \"#{path}\"" + end + + @matching_pattern_map + end + + def file_uploader_model_id + matchd = path_relative_to_upload_dir.match(FULL_PATH_CAPTURE) + not_found_msg = <<~MSG + Could not capture project full_path from a FileUploader path: + "#{path_relative_to_upload_dir}" + MSG + raise not_found_msg unless matchd + + full_path = matchd[1] + project = Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::Project.find_by_full_path(full_path) + return nil unless project + + project.id + end + + # Not including a leading slash + def path_relative_to_upload_dir + upload_dir = Gitlab::BackgroundMigration::PrepareUntrackedUploads::RELATIVE_UPLOAD_DIR # rubocop:disable Metrics/LineLength + base = %r{\A#{Regexp.escape(upload_dir)}/} + @path_relative_to_upload_dir ||= path.sub(base, '') + end + + def absolute_path + File.join(Gitlab.config.uploads.storage_path, path) + end + end + # Avoid using application code class Upload < ActiveRecord::Base self.table_name = 'uploads' -- cgit v1.2.1 From 2e216dd43bb02d741b2fcbfc1fe40042ad85a590 Mon Sep 17 00:00:00 2001 From: Dylan Griffith Date: Wed, 21 Feb 2018 16:27:05 +1100 Subject: Do not count rails sql cache as queries in query limiting --- lib/gitlab/query_limiting/active_support_subscriber.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/query_limiting/active_support_subscriber.rb b/lib/gitlab/query_limiting/active_support_subscriber.rb index 66049c94ec6..4c83581c4b1 100644 --- a/lib/gitlab/query_limiting/active_support_subscriber.rb +++ b/lib/gitlab/query_limiting/active_support_subscriber.rb @@ -3,8 +3,10 @@ module Gitlab class ActiveSupportSubscriber < ActiveSupport::Subscriber attach_to :active_record - def sql(*) - Transaction.current&.increment + def sql(event) + unless event.payload[:name] == 'CACHE' + Transaction.current&.increment + end end end end -- cgit v1.2.1 From 3b3615f0b78d728b9b3fa15971e4f597a9e3cb1d Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 20 Feb 2018 21:46:25 -0800 Subject: Guard against nil Sidekiq metrics server Closes #41351 --- lib/gitlab/metrics/sidekiq_metrics_exporter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/metrics/sidekiq_metrics_exporter.rb b/lib/gitlab/metrics/sidekiq_metrics_exporter.rb index 5980a4ded2b..db8bdde74b2 100644 --- a/lib/gitlab/metrics/sidekiq_metrics_exporter.rb +++ b/lib/gitlab/metrics/sidekiq_metrics_exporter.rb @@ -23,7 +23,7 @@ module Gitlab end def stop_working - server.shutdown + server.shutdown if server @server = nil end -- cgit v1.2.1 From c5e385bd5a0274e4d40e647eadcb22043f0f6e92 Mon Sep 17 00:00:00 2001 From: Ken Date: Wed, 21 Feb 2018 22:09:15 +1030 Subject: 36847 - update toml-rb to 1.0.0 36847 - add changelog --- lib/gitlab/setup_helper.rb | 2 +- lib/tasks/gitlab/gitaly.rake | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/setup_helper.rb b/lib/gitlab/setup_helper.rb index e90a90508a2..07d7c91cb5d 100644 --- a/lib/gitlab/setup_helper.rb +++ b/lib/gitlab/setup_helper.rb @@ -37,7 +37,7 @@ module Gitlab config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path } config[:bin_dir] = Gitlab.config.gitaly.client_path - TOML.dump(config) + TomlRB.dump(config) end # rubocop:disable Rails/Output diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake index 107ff1d8aeb..e9ca6404fe8 100644 --- a/lib/tasks/gitlab/gitaly.rake +++ b/lib/tasks/gitlab/gitaly.rake @@ -2,7 +2,7 @@ namespace :gitlab do namespace :gitaly do desc "GitLab | Install or upgrade gitaly" task :install, [:dir, :repo] => :gitlab_environment do |t, args| - require 'toml' + require 'toml-rb' warn_user_is_not_gitlab @@ -38,7 +38,7 @@ namespace :gitlab do desc "GitLab | Print storage configuration in TOML format" task storage_config: :environment do - require 'toml' + require 'toml-rb' puts "# Gitaly storage configuration generated from #{Gitlab.config.source} on #{Time.current.to_s(:long)}" puts "# This is in TOML format suitable for use in Gitaly's config.toml file." -- cgit v1.2.1 From 8bdfd8aa8789bb44c852398dd13866fc1ab44d29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A1rp=C3=A1ti=20L=C3=A1szl=C3=B3?= Date: Wed, 21 Feb 2018 15:57:26 +0000 Subject: Resolve "API: PUT /projects/:id fails when only ci_config_path is specified" --- lib/api/projects.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/api/projects.rb b/lib/api/projects.rb index e90892a90f7..b552b0e0c5d 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -271,6 +271,7 @@ module API [ :jobs_enabled, :resolve_outdated_diff_discussions, + :ci_config_path, :container_registry_enabled, :default_branch, :description, -- cgit v1.2.1 From 0c357ac83b941e3a3b5d13e8430ec555b384b967 Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Wed, 21 Feb 2018 10:04:42 -0800 Subject: Use convenient Rails helper --- lib/gitlab/background_migration/populate_untracked_uploads.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/background_migration/populate_untracked_uploads.rb b/lib/gitlab/background_migration/populate_untracked_uploads.rb index c5415bf0f9a..9232f20a063 100644 --- a/lib/gitlab/background_migration/populate_untracked_uploads.rb +++ b/lib/gitlab/background_migration/populate_untracked_uploads.rb @@ -83,7 +83,7 @@ module Gitlab end ids.each do |model_type, model_ids| - model_class = Object.const_get("Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::#{model_type}") + model_class = "Gitlab::BackgroundMigration::PopulateUntrackedUploadsDependencies::#{model_type}".constantize found_ids = model_class.where(id: model_ids.uniq).pluck(:id) deleted_ids = ids[model_type] - found_ids ids[model_type] = deleted_ids -- cgit v1.2.1 From e70fe78281ba07d9a0eb863d66ddf6a13917fde1 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Tue, 20 Feb 2018 09:06:00 +0100 Subject: Handle branch and tag names which are commit ids Adds a test where a branch name is also a valid commit id. Git, the binary should create an error message which is difficult to parse and leading to errors later, as seen in: gitlab-org/gitlab-ce#43222 To catch these cases in the future, gitlab-test@1942eed5cc108b19c7405106e81fa96125d0be22 was created. Which a branch name matching the commit --- lib/gitlab/git/repository.rb | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index a10bc0dd32b..072ad312ab8 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -1349,7 +1349,7 @@ module Gitlab if is_enabled gitaly_ref_client.branch_names_contains_sha(sha) else - refs_contains_sha(:branch, sha) + refs_contains_sha('refs/heads/', sha) end end end @@ -1359,7 +1359,7 @@ module Gitlab if is_enabled gitaly_ref_client.tag_names_contains_sha(sha) else - refs_contains_sha(:tag, sha) + refs_contains_sha('refs/tags/', sha) end end end @@ -1458,19 +1458,25 @@ module Gitlab end end - def refs_contains_sha(ref_type, sha) - args = %W(#{ref_type} --contains #{sha}) - names = run_git(args).first + def refs_contains_sha(refs_prefix, sha) + refs_prefix << "/" unless refs_prefix.ends_with?('/') - return [] unless names.respond_to?(:split) + # By forcing the output to %(refname) each line wiht a ref will start with + # the ref prefix. All other lines can be discarded. + args = %W(for-each-ref --contains=#{sha} --format=%(refname) #{refs_prefix}) + names, code = run_git(args) - names = names.split("\n").map(&:strip) + return [] unless code.zero? - names.each do |name| - name.slice! '* ' + refs = [] + left_slice_count = refs_prefix.length + names.lines.each do |line| + next unless line.start_with?(refs_prefix) + + refs << line.rstrip[left_slice_count..-1] end - names + refs end def rugged_write_config(full_path:) -- cgit v1.2.1 From acc0e25de739aa515dbf8ef151921f366fe322b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Wed, 7 Feb 2018 18:26:35 -0300 Subject: Incorporate Gitaly's RepositoryService.IsSquashInProgress RPC --- lib/gitlab/git/repository.rb | 8 +++++++- lib/gitlab/gitaly_client/repository_service.rb | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 6761fb0937a..14e98e39394 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -1234,7 +1234,13 @@ module Gitlab end def squash_in_progress?(squash_id) - fresh_worktree?(worktree_path(SQUASH_WORKTREE_PREFIX, squash_id)) + gitaly_migrate(:squash_in_progress) do |is_enabled| + if is_enabled + gitaly_repository_client.squash_in_progress?(squash_id) + else + fresh_worktree?(worktree_path(SQUASH_WORKTREE_PREFIX, squash_id)) + end + end end def push_remote_branches(remote_name, branch_names, forced: true) diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb index 60706b4f0d8..603457d0664 100644 --- a/lib/gitlab/gitaly_client/repository_service.rb +++ b/lib/gitlab/gitaly_client/repository_service.rb @@ -134,6 +134,23 @@ module Gitlab response.in_progress end + def squash_in_progress?(squash_id) + request = Gitaly::IsSquashInProgressRequest.new( + repository: @gitaly_repo, + squash_id: squash_id.to_s + ) + + response = GitalyClient.call( + @storage, + :repository_service, + :is_squash_in_progress, + request, + timeout: GitalyClient.default_timeout + ) + + response.in_progress + end + def fetch_source_branch(source_repository, source_branch, local_ref) request = Gitaly::FetchSourceBranchRequest.new( repository: @gitaly_repo, -- cgit v1.2.1 From ea18e1bf287800825f12e87cf3160e90cc2046d9 Mon Sep 17 00:00:00 2001 From: "Jacob Vosmaer (GitLab)" Date: Thu, 22 Feb 2018 00:20:30 +0000 Subject: Fix repo existence check in GitAccessWiki --- lib/gitlab/git_access.rb | 6 +++++- lib/gitlab/git_access_wiki.rb | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index 9ec3858b493..bbdb593d4e2 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -198,7 +198,7 @@ module Gitlab end def check_repository_existence! - unless project.repository.exists? + unless repository.exists? raise UnauthorizedError, ERROR_MESSAGES[:no_repo] end end @@ -327,5 +327,9 @@ module Gitlab def push_to_read_only_message ERROR_MESSAGES[:cannot_push_to_read_only] end + + def repository + project.repository + end end end diff --git a/lib/gitlab/git_access_wiki.rb b/lib/gitlab/git_access_wiki.rb index 84d6e1490c3..a5b3902ebf4 100644 --- a/lib/gitlab/git_access_wiki.rb +++ b/lib/gitlab/git_access_wiki.rb @@ -28,5 +28,11 @@ module Gitlab def push_to_read_only_message ERROR_MESSAGES[:read_only] end + + private + + def repository + project.wiki.repository + end end end -- cgit v1.2.1 From cdf3ae04f84abe039b79ab31192bb7c462bf7ce5 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 21 Feb 2018 13:42:11 +0000 Subject: Fix 500 error when diff context line has broken encoding Rugged sometimes chops a context line in between bytes, resulting in the context line having an invalid encoding: https://github.com/libgit2/rugged/issues/716 When that happens, we will try to detect the encoding for the diff, and sometimes we'll get it wrong. If that difference in encoding results in a difference in string lengths between the diff and the underlying blobs, we'd fail to highlight any inline diffs, and return a 500 status to the user. As we're using the underlying blobs, the encoding is 'correct' anyway, so if the string range is invalid, we can just discard the inline diff highlighting. We still report to Sentry to ensure that we can investigate further in future. --- lib/gitlab/diff/highlight.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/diff/highlight.rb b/lib/gitlab/diff/highlight.rb index 0f897e6316c..269016daac2 100644 --- a/lib/gitlab/diff/highlight.rb +++ b/lib/gitlab/diff/highlight.rb @@ -27,7 +27,17 @@ module Gitlab rich_line = highlight_line(diff_line) || diff_line.text if line_inline_diffs = inline_diffs[i] - rich_line = InlineDiffMarker.new(diff_line.text, rich_line).mark(line_inline_diffs) + begin + rich_line = InlineDiffMarker.new(diff_line.text, rich_line).mark(line_inline_diffs) + # This should only happen when the encoding of the diff doesn't + # match the blob, which is a bug. But we shouldn't fail to render + # completely in that case, even though we want to report the error. + rescue RangeError => e + if Gitlab::Sentry.enabled? + Gitlab::Sentry.context + Raven.capture_exception(e) + end + end end diff_line.text = rich_line -- cgit v1.2.1 From 148816cd67a314f17e79c107270cc708501bdd39 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Mon, 11 Dec 2017 15:21:06 +0100 Subject: Port `read_cross_project` ability from EE --- lib/api/helpers.rb | 2 +- lib/api/settings.rb | 2 +- .../cross_project_issuable_information_filter.rb | 40 +++++++++++++ lib/banzai/filter/issuable_state_filter.rb | 6 ++ lib/banzai/filter/milestone_reference_filter.rb | 2 +- lib/banzai/pipeline/post_process_pipeline.rb | 1 + lib/banzai/reference_parser/issuable_parser.rb | 2 +- lib/banzai/reference_parser/issue_parser.rb | 25 +++++++- lib/gitlab/contributions_calendar.rb | 6 ++ lib/gitlab/cross_project_access.rb | 67 ++++++++++++++++++++++ .../cross_project_access/check_collection.rb | 47 +++++++++++++++ lib/gitlab/cross_project_access/check_info.rb | 66 +++++++++++++++++++++ lib/gitlab/cross_project_access/class_methods.rb | 48 ++++++++++++++++ lib/gitlab/user_access.rb | 2 +- 14 files changed, 308 insertions(+), 8 deletions(-) create mode 100644 lib/banzai/filter/cross_project_issuable_information_filter.rb create mode 100644 lib/gitlab/cross_project_access.rb create mode 100644 lib/gitlab/cross_project_access/check_collection.rb create mode 100644 lib/gitlab/cross_project_access/check_info.rb create mode 100644 lib/gitlab/cross_project_access/class_methods.rb (limited to 'lib') diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 6134ad2bfc7..e4fca77ab5d 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -172,7 +172,7 @@ module API def find_project_snippet(id) finder_params = { project: user_project } - SnippetsFinder.new(current_user, finder_params).execute.find(id) + SnippetsFinder.new(current_user, finder_params).find(id) end def find_merge_request_with_access(iid, access_level = :read_merge_request) diff --git a/lib/api/settings.rb b/lib/api/settings.rb index cee4d309816..152df23a327 100644 --- a/lib/api/settings.rb +++ b/lib/api/settings.rb @@ -147,7 +147,7 @@ module API attrs[:password_authentication_enabled_for_web] = attrs.delete(:password_authentication_enabled) end - if current_settings.update_attributes(attrs) + if ApplicationSettings::UpdateService.new(current_settings, current_user, attrs).execute present current_settings, with: Entities::ApplicationSetting else render_validation_error!(current_settings) diff --git a/lib/banzai/filter/cross_project_issuable_information_filter.rb b/lib/banzai/filter/cross_project_issuable_information_filter.rb new file mode 100644 index 00000000000..c2c08b4fd6a --- /dev/null +++ b/lib/banzai/filter/cross_project_issuable_information_filter.rb @@ -0,0 +1,40 @@ +module Banzai + module Filter + # HTML filter that removes sensitive information from cross project + # issue references. + # + # The link to the issue or merge request is preserved only the IID is shown, + # but all other info is removed. + class CrossProjectIssuableInformationFilter < HTML::Pipeline::Filter + def call + return doc if can_read_cross_project? + + extractor = Banzai::IssuableExtractor.new(project, current_user) + issuables = extractor.extract([doc]) + + issuables.each do |node, issuable| + next if issuable.project == project + + node['class'] = node['class'].gsub('has-tooltip', '') + node['title'] = nil + end + + doc + end + + private + + def project + context[:project] + end + + def can_read_cross_project? + Ability.allowed?(current_user, :read_cross_project) + end + + def current_user + context[:current_user] + end + end + end +end diff --git a/lib/banzai/filter/issuable_state_filter.rb b/lib/banzai/filter/issuable_state_filter.rb index 327ea9449a1..77299abe324 100644 --- a/lib/banzai/filter/issuable_state_filter.rb +++ b/lib/banzai/filter/issuable_state_filter.rb @@ -15,6 +15,8 @@ module Banzai issuables = extractor.extract([doc]) issuables.each do |node, issuable| + next if !can_read_cross_project? && issuable.project != project + if VISIBLE_STATES.include?(issuable.state) && node.inner_html == issuable.reference_link_text(project) node.content += " (#{issuable.state})" end @@ -25,6 +27,10 @@ module Banzai private + def can_read_cross_project? + Ability.allowed?(current_user, :read_cross_project) + end + def current_user context[:current_user] end diff --git a/lib/banzai/filter/milestone_reference_filter.rb b/lib/banzai/filter/milestone_reference_filter.rb index 2a6b0964ac5..8ec696ce5fc 100644 --- a/lib/banzai/filter/milestone_reference_filter.rb +++ b/lib/banzai/filter/milestone_reference_filter.rb @@ -64,7 +64,7 @@ module Banzai finder_params[:group_ids] = [project.group.id] end - MilestonesFinder.new(finder_params).execute.find_by(params) + MilestonesFinder.new(finder_params).find_by(params) end def url_for_object(milestone, project) diff --git a/lib/banzai/pipeline/post_process_pipeline.rb b/lib/banzai/pipeline/post_process_pipeline.rb index dcd52bc03c7..4cf97e2d9d2 100644 --- a/lib/banzai/pipeline/post_process_pipeline.rb +++ b/lib/banzai/pipeline/post_process_pipeline.rb @@ -6,6 +6,7 @@ module Banzai Filter::RedactorFilter, Filter::RelativeLinkFilter, Filter::IssuableStateFilter, + Filter::CrossProjectIssuableInformationFilter, Filter::AbsoluteLinkFilter ] end diff --git a/lib/banzai/reference_parser/issuable_parser.rb b/lib/banzai/reference_parser/issuable_parser.rb index 3953867eb83..fad127d7e5b 100644 --- a/lib/banzai/reference_parser/issuable_parser.rb +++ b/lib/banzai/reference_parser/issuable_parser.rb @@ -18,7 +18,7 @@ module Banzai end def can_read_reference?(user, issuable) - can?(user, "read_#{issuable.class.to_s.underscore}".to_sym, issuable) + can?(user, "read_#{issuable.class.to_s.underscore}_iid".to_sym, issuable) end end end diff --git a/lib/banzai/reference_parser/issue_parser.rb b/lib/banzai/reference_parser/issue_parser.rb index 38d4e3f3e44..230827129b6 100644 --- a/lib/banzai/reference_parser/issue_parser.rb +++ b/lib/banzai/reference_parser/issue_parser.rb @@ -5,12 +5,31 @@ module Banzai def nodes_visible_to_user(user, nodes) issues = records_for_nodes(nodes) + issues_to_check = issues.values - readable_issues = Ability - .issues_readable_by_user(issues.values, user).to_set + unless can?(user, :read_cross_project) + issues_to_check, cross_project_issues = issues_to_check.partition do |issue| + issue.project == project + end + end + + readable_issues = Ability.issues_readable_by_user(issues_to_check, user).to_set nodes.select do |node| - readable_issues.include?(issues[node]) + issue_in_node = issues[node] + + # We check the inclusion of readable issues first because it's faster. + # + # But we need to fall back to `read_issue_iid` if the user cannot read + # cross project, since it might be possible the user can see the IID + # but not the issue. + if readable_issues.include?(issue_in_node) + true + elsif cross_project_issues&.include?(issue_in_node) + can_read_reference?(user, issue_in_node) + else + false + end end end diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb index 0735243e021..9576d5a3fd8 100644 --- a/lib/gitlab/contributions_calendar.rb +++ b/lib/gitlab/contributions_calendar.rb @@ -34,6 +34,8 @@ module Gitlab end def events_by_date(date) + return Event.none unless can_read_cross_project? + events = Event.contributions.where(author_id: contributor.id) .where(created_at: date.beginning_of_day..date.end_of_day) .where(project_id: projects) @@ -53,6 +55,10 @@ module Gitlab private + def can_read_cross_project? + Ability.allowed?(current_user, :read_cross_project) + end + def event_counts(date_from, feature) t = Event.arel_table diff --git a/lib/gitlab/cross_project_access.rb b/lib/gitlab/cross_project_access.rb new file mode 100644 index 00000000000..6eaed51b64c --- /dev/null +++ b/lib/gitlab/cross_project_access.rb @@ -0,0 +1,67 @@ +module Gitlab + class CrossProjectAccess + class << self + delegate :add_check, :find_check, :checks, + to: :instance + end + + def self.instance + @instance ||= new + end + + attr_reader :checks + + def initialize + @checks = {} + end + + def add_check( + klass, + actions: {}, + positive_condition: nil, + negative_condition: nil, + skip: false) + + new_check = CheckInfo.new(actions, + positive_condition, + negative_condition, + skip + ) + + @checks[klass] ||= Gitlab::CrossProjectAccess::CheckCollection.new + @checks[klass].add_check(new_check) + recalculate_checks_for_class(klass) + + @checks[klass] + end + + def find_check(object) + @cached_checks ||= Hash.new do |cache, new_class| + parent_classes = @checks.keys.select { |existing_class| new_class <= existing_class } + closest_class = closest_parent(parent_classes, new_class) + cache[new_class] = @checks[closest_class] + end + + @cached_checks[object.class] + end + + private + + def recalculate_checks_for_class(klass) + new_collection = @checks[klass] + + @checks.each do |existing_class, existing_check_collection| + if existing_class < klass + existing_check_collection.add_collection(new_collection) + elsif klass < existing_class + new_collection.add_collection(existing_check_collection) + end + end + end + + def closest_parent(classes, subject) + relevant_ancestors = subject.ancestors & classes + relevant_ancestors.first + end + end +end diff --git a/lib/gitlab/cross_project_access/check_collection.rb b/lib/gitlab/cross_project_access/check_collection.rb new file mode 100644 index 00000000000..88376232065 --- /dev/null +++ b/lib/gitlab/cross_project_access/check_collection.rb @@ -0,0 +1,47 @@ +module Gitlab + class CrossProjectAccess + class CheckCollection + attr_reader :checks + + def initialize + @checks = [] + end + + def add_collection(collection) + @checks |= collection.checks + end + + def add_check(check) + @checks << check + end + + def should_run?(object) + skips, runs = arranged_checks + + # If one rule tells us to skip, we skip the cross project check + return false if skips.any? { |check| check.should_skip?(object) } + + # If the rule isn't skipped, we run it if any of the checks says we + # should run + runs.any? { |check| check.should_run?(object) } + end + + def arranged_checks + return [@skips, @runs] if @skips && @runs + + @skips = [] + @runs = [] + + @checks.each do |check| + if check.skip + @skips << check + else + @runs << check + end + end + + [@skips, @runs] + end + end + end +end diff --git a/lib/gitlab/cross_project_access/check_info.rb b/lib/gitlab/cross_project_access/check_info.rb new file mode 100644 index 00000000000..e8a845c7f1e --- /dev/null +++ b/lib/gitlab/cross_project_access/check_info.rb @@ -0,0 +1,66 @@ +module Gitlab + class CrossProjectAccess + class CheckInfo + attr_accessor :actions, :positive_condition, :negative_condition, :skip + + def initialize(actions, positive_condition, negative_condition, skip) + @actions = actions + @positive_condition = positive_condition + @negative_condition = negative_condition + @skip = skip + end + + def should_skip?(object) + return !should_run?(object) unless @skip + + skip_for_action = @actions[current_action(object)] + skip_for_action = false if @actions[current_action(object)].nil? + + # We need to do the opposite of what was defined in the following cases: + # - skip_cross_project_access_check index: true, if: -> { false } + # - skip_cross_project_access_check index: true, unless: -> { true } + if positive_condition_is_false?(object) + skip_for_action = !skip_for_action + end + + if negative_condition_is_true?(object) + skip_for_action = !skip_for_action + end + + skip_for_action + end + + def should_run?(object) + return !should_skip?(object) if @skip + + run_for_action = @actions[current_action(object)] + run_for_action = true if @actions[current_action(object)].nil? + + # We need to do the opposite of what was defined in the following cases: + # - requires_cross_project_access index: true, if: -> { false } + # - requires_cross_project_access index: true, unless: -> { true } + if positive_condition_is_false?(object) + run_for_action = !run_for_action + end + + if negative_condition_is_true?(object) + run_for_action = !run_for_action + end + + run_for_action + end + + def positive_condition_is_false?(object) + @positive_condition && !object.instance_exec(&@positive_condition) + end + + def negative_condition_is_true?(object) + @negative_condition && object.instance_exec(&@negative_condition) + end + + def current_action(object) + object.respond_to?(:action_name) ? object.action_name.to_sym : nil + end + end + end +end diff --git a/lib/gitlab/cross_project_access/class_methods.rb b/lib/gitlab/cross_project_access/class_methods.rb new file mode 100644 index 00000000000..90eac94800c --- /dev/null +++ b/lib/gitlab/cross_project_access/class_methods.rb @@ -0,0 +1,48 @@ +module Gitlab + class CrossProjectAccess + module ClassMethods + def requires_cross_project_access(*args) + positive_condition, negative_condition, actions = extract_params(args) + + Gitlab::CrossProjectAccess.add_check( + self, + actions: actions, + positive_condition: positive_condition, + negative_condition: negative_condition + ) + end + + def skip_cross_project_access_check(*args) + positive_condition, negative_condition, actions = extract_params(args) + + Gitlab::CrossProjectAccess.add_check( + self, + actions: actions, + positive_condition: positive_condition, + negative_condition: negative_condition, + skip: true + ) + end + + private + + def extract_params(args) + actions = {} + positive_condition = nil + negative_condition = nil + + args.each do |argument| + if argument.is_a?(Hash) + positive_condition = argument.delete(:if) + negative_condition = argument.delete(:unless) + actions.merge!(argument) + else + actions[argument] = true + end + end + + [positive_condition, negative_condition, actions] + end + end + end +end diff --git a/lib/gitlab/user_access.rb b/lib/gitlab/user_access.rb index 15eb1c41213..ff4dc29efea 100644 --- a/lib/gitlab/user_access.rb +++ b/lib/gitlab/user_access.rb @@ -65,7 +65,7 @@ module Gitlab return false unless can_access_git? if protected?(ProtectedBranch, project, ref) - return true if project.empty_repo? && project.user_can_push_to_empty_repo?(user) + return true if project.user_can_push_to_empty_repo?(user) protected_branch_accessible_to?(ref, action: :push) else -- cgit v1.2.1 From 08266ba0a14ec296b51cda6b54d1648985a11adf Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 21 Feb 2018 12:50:13 +0100 Subject: Use `Redactor` to hide cross project information Since the redactor can be run on multiple documents at once and query results are stored in the request store. --- .../cross_project_issuable_information_filter.rb | 40 ---------------------- lib/banzai/pipeline/post_process_pipeline.rb | 1 - lib/banzai/redactor.rb | 21 +++++++++++- 3 files changed, 20 insertions(+), 42 deletions(-) delete mode 100644 lib/banzai/filter/cross_project_issuable_information_filter.rb (limited to 'lib') diff --git a/lib/banzai/filter/cross_project_issuable_information_filter.rb b/lib/banzai/filter/cross_project_issuable_information_filter.rb deleted file mode 100644 index c2c08b4fd6a..00000000000 --- a/lib/banzai/filter/cross_project_issuable_information_filter.rb +++ /dev/null @@ -1,40 +0,0 @@ -module Banzai - module Filter - # HTML filter that removes sensitive information from cross project - # issue references. - # - # The link to the issue or merge request is preserved only the IID is shown, - # but all other info is removed. - class CrossProjectIssuableInformationFilter < HTML::Pipeline::Filter - def call - return doc if can_read_cross_project? - - extractor = Banzai::IssuableExtractor.new(project, current_user) - issuables = extractor.extract([doc]) - - issuables.each do |node, issuable| - next if issuable.project == project - - node['class'] = node['class'].gsub('has-tooltip', '') - node['title'] = nil - end - - doc - end - - private - - def project - context[:project] - end - - def can_read_cross_project? - Ability.allowed?(current_user, :read_cross_project) - end - - def current_user - context[:current_user] - end - end - end -end diff --git a/lib/banzai/pipeline/post_process_pipeline.rb b/lib/banzai/pipeline/post_process_pipeline.rb index 4cf97e2d9d2..dcd52bc03c7 100644 --- a/lib/banzai/pipeline/post_process_pipeline.rb +++ b/lib/banzai/pipeline/post_process_pipeline.rb @@ -6,7 +6,6 @@ module Banzai Filter::RedactorFilter, Filter::RelativeLinkFilter, Filter::IssuableStateFilter, - Filter::CrossProjectIssuableInformationFilter, Filter::AbsoluteLinkFilter ] end diff --git a/lib/banzai/redactor.rb b/lib/banzai/redactor.rb index de3ebe72720..827df7c08ae 100644 --- a/lib/banzai/redactor.rb +++ b/lib/banzai/redactor.rb @@ -19,8 +19,9 @@ module Banzai # # Returns the documents passed as the first argument. def redact(documents) - all_document_nodes = document_nodes(documents) + redact_cross_project_references(documents) unless can_read_cross_project? + all_document_nodes = document_nodes(documents) redact_document_nodes(all_document_nodes) end @@ -51,6 +52,18 @@ module Banzai metadata end + def redact_cross_project_references(documents) + extractor = Banzai::IssuableExtractor.new(project, user) + issuables = extractor.extract(documents) + + issuables.each do |node, issuable| + next if issuable.project == project + + node['class'] = node['class'].gsub('has-tooltip', '') + node['title'] = nil + end + end + # Returns the nodes visible to the current user. # # nodes - The input nodes to check. @@ -78,5 +91,11 @@ module Banzai { document: document, nodes: Querying.css(document, 'a.gfm[data-reference-type]') } end end + + private + + def can_read_cross_project? + Ability.allowed?(user, :read_cross_project) + end end end -- cgit v1.2.1 From 41bfe82b7a650f21b19a25204dde5a0eaf960d0f Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 15 Feb 2018 19:34:44 +0100 Subject: Optimise searching for users using short queries This optimises searching for users when using queries consisting out of one or two characters such as "ab". We optimise such cases by searching for `LOWER(name)` and `LOWER(username)` instead of using `ILIKE`. Using `LOWER` produces a _much_ better performing query. For example, when searching for all users matching the term "a" we'd produce the following plan: Limit (cost=637.69..637.74 rows=20 width=805) (actual time=41.983..41.995 rows=20 loops=1) Buffers: shared hit=8330 -> Sort (cost=637.69..638.61 rows=368 width=805) (actual time=41.982..41.990 rows=20 loops=1) Sort Key: (CASE WHEN ((name)::text = 'a'::text) THEN 0 WHEN ((username)::text = 'a'::text) THEN 1 WHEN ((email)::text = 'a'::text) THEN 2 ELSE 3 END), name Sort Method: top-N heapsort Memory: 35kB Buffers: shared hit=8330 -> Bitmap Heap Scan on users (cost=75.47..627.89 rows=368 width=805) (actual time=9.452..41.305 rows=277 loops=1) Recheck Cond: (((name)::text ~~* 'a'::text) OR ((username)::text ~~* 'a'::text) OR ((email)::text = 'a'::text)) Rows Removed by Index Recheck: 7601 Heap Blocks: exact=7636 Buffers: shared hit=8327 -> BitmapOr (cost=75.47..75.47 rows=368 width=0) (actual time=8.290..8.290 rows=0 loops=1) Buffers: shared hit=691 -> Bitmap Index Scan on index_users_on_name_trigram (cost=0.00..38.85 rows=180 width=0) (actual time=4.369..4.369 rows=4071 loops=1) Index Cond: ((name)::text ~~* 'a'::text) Buffers: shared hit=360 -> Bitmap Index Scan on index_users_on_username_trigram (cost=0.00..34.41 rows=188 width=0) (actual time=3.896..3.896 rows=4140 loops=1) Index Cond: ((username)::text ~~* 'a'::text) Buffers: shared hit=328 -> Bitmap Index Scan on users_email_key (cost=0.00..1.94 rows=1 width=0) (actual time=0.022..0.022 rows=0 loops=1) Index Cond: ((email)::text = 'a'::text) Buffers: shared hit=3 Planning time: 3.912 ms Execution time: 42.171 ms With the changes in this commit we now produce the following plan instead: Limit (cost=13257.48..13257.53 rows=20 width=805) (actual time=1.567..1.579 rows=20 loops=1) Buffers: shared hit=287 -> Sort (cost=13257.48..13280.93 rows=9379 width=805) (actual time=1.567..1.572 rows=20 loops=1) Sort Key: (CASE WHEN ((name)::text = 'a'::text) THEN 0 WHEN ((username)::text = 'a'::text) THEN 1 WHEN ((email)::text = 'a'::text) THEN 2 ELSE 3 END), name Sort Method: top-N heapsort Memory: 35kB Buffers: shared hit=287 -> Bitmap Heap Scan on users (cost=135.66..13007.91 rows=9379 width=805) (actual time=0.194..1.107 rows=277 loops=1) Recheck Cond: ((lower((name)::text) = 'a'::text) OR (lower((username)::text) = 'a'::text) OR ((email)::text = 'a'::text)) Heap Blocks: exact=277 Buffers: shared hit=287 -> BitmapOr (cost=135.66..135.66 rows=9379 width=0) (actual time=0.152..0.152 rows=0 loops=1) Buffers: shared hit=10 -> Bitmap Index Scan on yorick_test_users (cost=0.00..124.75 rows=9377 width=0) (actual time=0.101..0.101 rows=277 loops=1) Index Cond: (lower((name)::text) = 'a'::text) Buffers: shared hit=4 -> Bitmap Index Scan on index_on_users_lower_username (cost=0.00..1.94 rows=1 width=0) (actual time=0.035..0.035 rows=1 loops=1) Index Cond: (lower((username)::text) = 'a'::text) Buffers: shared hit=3 -> Bitmap Index Scan on users_email_key (cost=0.00..1.94 rows=1 width=0) (actual time=0.014..0.014 rows=0 loops=1) Index Cond: ((email)::text = 'a'::text) Buffers: shared hit=3 Planning time: 0.303 ms Execution time: 1.687 ms Here we can see the new query is 25 times faster compared to the old query. --- lib/gitlab/sql/pattern.rb | 16 ++++++++++++++-- lib/tasks/migrate/setup_postgresql.rake | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/sql/pattern.rb b/lib/gitlab/sql/pattern.rb index 5f0c98cb5a4..0e3a93aa236 100644 --- a/lib/gitlab/sql/pattern.rb +++ b/lib/gitlab/sql/pattern.rb @@ -25,7 +25,11 @@ module Gitlab query.length >= MIN_CHARS_FOR_PARTIAL_MATCHING end - def fuzzy_arel_match(column, query) + # column - The column name to search in. + # query - The text to search for. + # lower_exact_match - When set to `true` we'll fall back to using + # `LOWER(column) = query` instead of using `ILIKE`. + def fuzzy_arel_match(column, query, lower_exact_match: false) query = query.squish return nil unless query.present? @@ -34,9 +38,17 @@ module Gitlab if words.any? words.map { |word| arel_table[column].matches(to_pattern(word)) }.reduce(:and) else + sanitized_query = sanitize_sql_like(query) + # No words of at least 3 chars, but we can search for an exact # case insensitive match with the query as a whole - arel_table[column].matches(sanitize_sql_like(query)) + if lower_exact_match + Arel::Nodes::NamedFunction + .new('LOWER', [arel_table[column]]) + .eq(sanitized_query) + else + arel_table[column].matches(sanitized_query) + end end end diff --git a/lib/tasks/migrate/setup_postgresql.rake b/lib/tasks/migrate/setup_postgresql.rake index 31cbd651edb..1c7a8a90f5c 100644 --- a/lib/tasks/migrate/setup_postgresql.rake +++ b/lib/tasks/migrate/setup_postgresql.rake @@ -8,6 +8,7 @@ task setup_postgresql: :environment do require Rails.root.join('db/migrate/20170503185032_index_redirect_routes_path_for_like') require Rails.root.join('db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb') require Rails.root.join('db/migrate/20180113220114_rework_redirect_routes_indexes.rb') + require Rails.root.join('db/migrate/20180215181245_users_name_lower_index.rb') NamespacesProjectsPathLowerIndexes.new.up AddUsersLowerUsernameEmailIndexes.new.up @@ -17,4 +18,5 @@ task setup_postgresql: :environment do IndexRedirectRoutesPathForLike.new.up AddIndexOnNamespacesLowerName.new.up ReworkRedirectRoutesIndexes.new.up + UsersNameLowerIndex.new.up end -- cgit v1.2.1 From 090eeb581b3809ab83d52f7baa2bcfbd63b1c2ba Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 15 Feb 2018 19:55:43 +0100 Subject: Added changelog for user search improvements --- lib/gitlab/sql/pattern.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/sql/pattern.rb b/lib/gitlab/sql/pattern.rb index 0e3a93aa236..53744bad1f4 100644 --- a/lib/gitlab/sql/pattern.rb +++ b/lib/gitlab/sql/pattern.rb @@ -38,16 +38,14 @@ module Gitlab if words.any? words.map { |word| arel_table[column].matches(to_pattern(word)) }.reduce(:and) else - sanitized_query = sanitize_sql_like(query) - # No words of at least 3 chars, but we can search for an exact # case insensitive match with the query as a whole if lower_exact_match Arel::Nodes::NamedFunction .new('LOWER', [arel_table[column]]) - .eq(sanitized_query) + .eq(query) else - arel_table[column].matches(sanitized_query) + arel_table[column].matches(sanitize_sql_like(query)) end end end -- cgit v1.2.1 From 14978ddc53d3ae80a87198d543dbdd14674390dd Mon Sep 17 00:00:00 2001 From: Mayra Cabrera Date: Thu, 22 Feb 2018 15:13:30 -0600 Subject: Modify cluster creation API method to enable legacy_apac as default GKE 1.8 has RBAC on by default, since GKE has bumped the default version to 1.8.7 RBAC is now on, and we don't support that out of the box. This was also avoiding cluster applications (tiller, prometheus, etc), to be installed. Closes #41619 --- lib/google_api/cloud_platform/client.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/google_api/cloud_platform/client.rb b/lib/google_api/cloud_platform/client.rb index ff638c07755..f30dd995695 100644 --- a/lib/google_api/cloud_platform/client.rb +++ b/lib/google_api/cloud_platform/client.rb @@ -76,9 +76,13 @@ module GoogleApi "initial_node_count": cluster_size, "node_config": { "machine_type": machine_type + }, + "legacy_abac": { + "enabled": true } } - } ) + } + ) service.create_cluster(project_id, zone, request_body, options: user_agent_header) end -- cgit v1.2.1 From 7a6c7bd66bae678640c98ad426cd0153f638b163 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Fri, 23 Feb 2018 10:33:46 +0000 Subject: Allow token authentication on go-get request --- lib/gitlab/auth/request_authenticator.rb | 8 ++++++++ lib/gitlab/middleware/go.rb | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/auth/request_authenticator.rb b/lib/gitlab/auth/request_authenticator.rb index 46ec040ce92..a0b5cd868c3 100644 --- a/lib/gitlab/auth/request_authenticator.rb +++ b/lib/gitlab/auth/request_authenticator.rb @@ -20,6 +20,14 @@ module Gitlab rescue Gitlab::Auth::AuthenticationError nil end + + def valid_access_token?(scopes: []) + validate_access_token!(scopes: scopes) + + true + rescue Gitlab::Auth::AuthenticationError + false + end end end end diff --git a/lib/gitlab/middleware/go.rb b/lib/gitlab/middleware/go.rb index 1a570f480c6..1fd8f147b44 100644 --- a/lib/gitlab/middleware/go.rb +++ b/lib/gitlab/middleware/go.rb @@ -114,7 +114,15 @@ module Gitlab end def current_user(request) - request.env['warden']&.authenticate + authenticator = Gitlab::Auth::RequestAuthenticator.new(request) + user = authenticator.find_user_from_access_token || authenticator.find_user_from_warden + + return unless user&.can?(:access_api) + + # Right now, the `api` scope is the only one that should be able to determine private project existence. + return unless authenticator.valid_access_token?(scopes: [:api]) + + user end end end -- cgit v1.2.1 From ee68bd9771f671ce7c258a8f5441125f1a9c2d53 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 6 Feb 2018 13:25:46 +0000 Subject: Add DNS verification to Pages custom domains --- lib/api/entities.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib') diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 45c737c6c29..167878ba600 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -1154,6 +1154,10 @@ module API expose :domain expose :url expose :project_id + expose :verified?, as: :verified + expose :verification_code, as: :verification_code + expose :enabled_until + expose :certificate, as: :certificate_expiration, if: ->(pages_domain, _) { pages_domain.certificate? }, @@ -1165,6 +1169,10 @@ module API class PagesDomain < Grape::Entity expose :domain expose :url + expose :verified?, as: :verified + expose :verification_code, as: :verification_code + expose :enabled_until + expose :certificate, if: ->(pages_domain, _) { pages_domain.certificate? }, using: PagesDomainCertificate do |pages_domain| -- cgit v1.2.1 From 57719d34d3fcc15f39354b0e9dc1da41bbe5d1a8 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 22 Feb 2018 18:34:04 +0100 Subject: Expose ChatName objects to slash commands Instead of only exposing a User to slash commands we now also expose the ChatName object that the User object is retrieved from. This is necessary for GitLab Chatops as we need for example the user ID of the chat user. --- lib/gitlab/slash_commands/base_command.rb | 7 ++++--- lib/gitlab/slash_commands/command.rb | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/slash_commands/base_command.rb b/lib/gitlab/slash_commands/base_command.rb index cc3c9a50555..466554e398c 100644 --- a/lib/gitlab/slash_commands/base_command.rb +++ b/lib/gitlab/slash_commands/base_command.rb @@ -31,10 +31,11 @@ module Gitlab raise NotImplementedError end - attr_accessor :project, :current_user, :params + attr_accessor :project, :current_user, :params, :chat_name - def initialize(project, user, params = {}) - @project, @current_user, @params = project, user, params.dup + def initialize(project, chat_name, params = {}) + @project, @current_user, @params = project, chat_name.user, params.dup + @chat_name = chat_name end private diff --git a/lib/gitlab/slash_commands/command.rb b/lib/gitlab/slash_commands/command.rb index a78408b0519..85aaa6b0eba 100644 --- a/lib/gitlab/slash_commands/command.rb +++ b/lib/gitlab/slash_commands/command.rb @@ -13,12 +13,13 @@ module Gitlab if command if command.allowed?(project, current_user) - command.new(project, current_user, params).execute(match) + command.new(project, chat_name, params).execute(match) else Gitlab::SlashCommands::Presenters::Access.new.access_denied end else - Gitlab::SlashCommands::Help.new(project, current_user, params).execute(available_commands, params[:text]) + Gitlab::SlashCommands::Help.new(project, chat_name, params) + .execute(available_commands, params[:text]) end end -- cgit v1.2.1 From ec9cb6edba9c99241984506e3a098187f4cb1fbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=99=88=20=20jacopo=20beschi=20=F0=9F=99=89?= Date: Fri, 23 Feb 2018 14:23:09 +0000 Subject: Resolve "Milestone Quick Action not displayed with no project milestones but with group milestones" --- lib/gitlab/quick_actions/command_definition.rb | 15 ++++++--------- lib/gitlab/quick_actions/dsl.rb | 5 ++--- lib/gitlab/quick_actions/extractor.rb | 10 +++++----- 3 files changed, 13 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/quick_actions/command_definition.rb b/lib/gitlab/quick_actions/command_definition.rb index 3937d9c153a..96415271316 100644 --- a/lib/gitlab/quick_actions/command_definition.rb +++ b/lib/gitlab/quick_actions/command_definition.rb @@ -24,15 +24,14 @@ module Gitlab action_block.nil? end - def available?(opts) + def available?(context) return true unless condition_block - context = OpenStruct.new(opts) context.instance_exec(&condition_block) end - def explain(context, opts, arg) - return unless available?(opts) + def explain(context, arg) + return unless available?(context) if explanation.respond_to?(:call) execute_block(explanation, context, arg) @@ -41,15 +40,13 @@ module Gitlab end end - def execute(context, opts, arg) - return if noop? || !available?(opts) + def execute(context, arg) + return if noop? || !available?(context) execute_block(action_block, context, arg) end - def to_h(opts) - context = OpenStruct.new(opts) - + def to_h(context) desc = description if desc.respond_to?(:call) desc = context.instance_exec(&desc) rescue '' diff --git a/lib/gitlab/quick_actions/dsl.rb b/lib/gitlab/quick_actions/dsl.rb index 536765305e1..d82dccd0db5 100644 --- a/lib/gitlab/quick_actions/dsl.rb +++ b/lib/gitlab/quick_actions/dsl.rb @@ -62,9 +62,8 @@ module Gitlab # Allows to define conditions that must be met in order for the command # to be returned by `.command_names` & `.command_definitions`. - # It accepts a block that will be evaluated with the context given to - # `CommandDefintion#to_h`. - # + # It accepts a block that will be evaluated with the context + # of a QuickActions::InterpretService instance # Example: # # condition do diff --git a/lib/gitlab/quick_actions/extractor.rb b/lib/gitlab/quick_actions/extractor.rb index c0878a34fb1..075ff91700c 100644 --- a/lib/gitlab/quick_actions/extractor.rb +++ b/lib/gitlab/quick_actions/extractor.rb @@ -29,7 +29,7 @@ module Gitlab # commands = extractor.extract_commands(msg) #=> [['labels', '~foo ~"bar baz"']] # msg #=> "hello\nworld" # ``` - def extract_commands(content, opts = {}) + def extract_commands(content) return [content, []] unless content content = content.dup @@ -37,7 +37,7 @@ module Gitlab commands = [] content.delete!("\r") - content.gsub!(commands_regex(opts)) do + content.gsub!(commands_regex) do if $~[:cmd] commands << [$~[:cmd], $~[:arg]].reject(&:blank?) '' @@ -60,8 +60,8 @@ module Gitlab # It looks something like: # # /^\/(?close|reopen|...)(?:( |$))(?[^\/\n]*)(?:\n|$)/ - def commands_regex(opts) - names = command_names(opts).map(&:to_s) + def commands_regex + names = command_names.map(&:to_s) @commands_regex ||= %r{ (? @@ -133,7 +133,7 @@ module Gitlab [content, commands] end - def command_names(opts) + def command_names command_definitions.flat_map do |command| next if command.noop? -- cgit v1.2.1 From 0e97eca1d8209a790ab34898e0c5f815bb0565de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chojnacki?= Date: Fri, 23 Feb 2018 17:58:40 +0000 Subject: Backport custom metrics ce components --- lib/gitlab/prometheus/metric_group.rb | 7 ++++- .../queries/additional_metrics_deployment_query.rb | 1 + .../additional_metrics_environment_query.rb | 1 + .../prometheus/queries/matched_metrics_query.rb | 2 +- .../prometheus/queries/query_additional_metrics.rb | 8 +++--- lib/gitlab/prometheus_client.rb | 33 ++++++++++++---------- 6 files changed, 31 insertions(+), 21 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/prometheus/metric_group.rb b/lib/gitlab/prometheus/metric_group.rb index 729fef34b35..e91c6fb2e27 100644 --- a/lib/gitlab/prometheus/metric_group.rb +++ b/lib/gitlab/prometheus/metric_group.rb @@ -6,9 +6,14 @@ module Gitlab attr_accessor :name, :priority, :metrics validates :name, :priority, :metrics, presence: true - def self.all + def self.common_metrics AdditionalMetricsParser.load_groups_from_yaml end + + # EE only + def self.for_project(_) + common_metrics + end end end end diff --git a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb index 294a6ae34ca..972ab75d1d5 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_deployment_query.rb @@ -7,6 +7,7 @@ module Gitlab def query(environment_id, deployment_id) Deployment.find_by(id: deployment_id).try do |deployment| query_metrics( + deployment.project, common_query_context( deployment.environment, timeframe_start: (deployment.created_at - 30.minutes).to_f, diff --git a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb index 32fe8201a8d..9273e69e158 100644 --- a/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb +++ b/lib/gitlab/prometheus/queries/additional_metrics_environment_query.rb @@ -7,6 +7,7 @@ module Gitlab def query(environment_id) ::Environment.find_by(id: environment_id).try do |environment| query_metrics( + environment.project, common_query_context(environment, timeframe_start: 8.hours.ago.to_f, timeframe_end: Time.now.to_f) ) end diff --git a/lib/gitlab/prometheus/queries/matched_metrics_query.rb b/lib/gitlab/prometheus/queries/matched_metrics_query.rb index 4c3edccc71a..5710ad47c1a 100644 --- a/lib/gitlab/prometheus/queries/matched_metrics_query.rb +++ b/lib/gitlab/prometheus/queries/matched_metrics_query.rb @@ -18,7 +18,7 @@ module Gitlab private def groups_data - metrics_groups = groups_with_active_metrics(Gitlab::Prometheus::MetricGroup.all) + metrics_groups = groups_with_active_metrics(Gitlab::Prometheus::MetricGroup.common_metrics) lookup = active_series_lookup(metrics_groups) groups = {} diff --git a/lib/gitlab/prometheus/queries/query_additional_metrics.rb b/lib/gitlab/prometheus/queries/query_additional_metrics.rb index 5cddc96a643..0c280dc9a3c 100644 --- a/lib/gitlab/prometheus/queries/query_additional_metrics.rb +++ b/lib/gitlab/prometheus/queries/query_additional_metrics.rb @@ -2,10 +2,10 @@ module Gitlab module Prometheus module Queries module QueryAdditionalMetrics - def query_metrics(query_context) + def query_metrics(project, query_context) query_processor = method(:process_query).curry[query_context] - groups = matched_metrics.map do |group| + groups = matched_metrics(project).map do |group| metrics = group.metrics.map do |metric| { title: metric.title, @@ -60,8 +60,8 @@ module Gitlab @available_metrics ||= client_label_values || [] end - def matched_metrics - result = Gitlab::Prometheus::MetricGroup.all.map do |group| + def matched_metrics(project) + result = Gitlab::Prometheus::MetricGroup.for_project(project).map do |group| group.metrics.select! do |metric| metric.required_metrics.all?(&available_metrics.method(:include?)) end diff --git a/lib/gitlab/prometheus_client.rb b/lib/gitlab/prometheus_client.rb index 10527972663..659021c9ac9 100644 --- a/lib/gitlab/prometheus_client.rb +++ b/lib/gitlab/prometheus_client.rb @@ -1,8 +1,9 @@ module Gitlab - PrometheusError = Class.new(StandardError) - # Helper methods to interact with Prometheus network services & resources class PrometheusClient + Error = Class.new(StandardError) + QueryError = Class.new(Gitlab::PrometheusClient::Error) + attr_reader :rest_client, :headers def initialize(rest_client) @@ -22,10 +23,10 @@ module Gitlab def query_range(query, start: 8.hours.ago, stop: Time.now) get_result('matrix') do json_api_get('query_range', - query: query, - start: start.to_f, - end: stop.to_f, - step: 1.minute.to_i) + query: query, + start: start.to_f, + end: stop.to_f, + step: 1.minute.to_i) end end @@ -43,22 +44,22 @@ module Gitlab path = ['api', 'v1', type].join('/') get(path, args) rescue JSON::ParserError - raise PrometheusError, 'Parsing response failed' + raise PrometheusClient::Error, 'Parsing response failed' rescue Errno::ECONNREFUSED - raise PrometheusError, 'Connection refused' + raise PrometheusClient::Error, 'Connection refused' end def get(path, args) response = rest_client[path].get(params: args) handle_response(response) rescue SocketError - raise PrometheusError, "Can't connect to #{rest_client.url}" + raise PrometheusClient::Error, "Can't connect to #{rest_client.url}" rescue OpenSSL::SSL::SSLError - raise PrometheusError, "#{rest_client.url} contains invalid SSL data" + raise PrometheusClient::Error, "#{rest_client.url} contains invalid SSL data" rescue RestClient::ExceptionWithResponse => ex handle_exception_response(ex.response) rescue RestClient::Exception - raise PrometheusError, "Network connection error" + raise PrometheusClient::Error, "Network connection error" end def handle_response(response) @@ -66,16 +67,18 @@ module Gitlab if response.code == 200 && json_data['status'] == 'success' json_data['data'] || {} else - raise PrometheusError, "#{response.code} - #{response.body}" + raise PrometheusClient::Error, "#{response.code} - #{response.body}" end end def handle_exception_response(response) - if response.code == 400 + if response.code == 200 && response['status'] == 'success' + response['data'] || {} + elsif response.code == 400 json_data = JSON.parse(response.body) - raise PrometheusError, json_data['error'] || 'Bad data received' + raise PrometheusClient::QueryError, json_data['error'] || 'Bad data received' else - raise PrometheusError, "#{response.code} - #{response.body}" + raise PrometheusClient::Error, "#{response.code} - #{response.body}" end end -- cgit v1.2.1 From 4be20ba923c010c105e30ef8bba3b9bf82b2d0ca Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Thu, 22 Feb 2018 10:51:00 -0800 Subject: Respond 404 when repo does not exist --- lib/gitlab/git_access.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/git_access.rb b/lib/gitlab/git_access.rb index bbdb593d4e2..6400089a22f 100644 --- a/lib/gitlab/git_access.rb +++ b/lib/gitlab/git_access.rb @@ -199,7 +199,7 @@ module Gitlab def check_repository_existence! unless repository.exists? - raise UnauthorizedError, ERROR_MESSAGES[:no_repo] + raise NotFoundError, ERROR_MESSAGES[:no_repo] end end -- cgit v1.2.1 From e351f67874fb98d1d40bd32dca8d9a44a4fc8582 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Fri, 23 Feb 2018 14:25:14 +0000 Subject: Suppress whitespace warnings in squash error messages These are obscuring the real error, which is confusing for everyone. --- lib/gitlab/git/repository.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index e3cbf017e55..ddb9cf433eb 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -2206,7 +2206,7 @@ module Gitlab with_worktree(squash_path, branch, sparse_checkout_files: diff_files, env: env) do # Apply diff of the `diff_range` to the worktree diff = run_git!(%W(diff --binary #{diff_range})) - run_git!(%w(apply --index), chdir: squash_path, env: env) do |stdin| + run_git!(%w(apply --index --whitespace=nowarn), chdir: squash_path, env: env) do |stdin| stdin.binmode stdin.write(diff) end -- cgit v1.2.1 From 006753110a462e62f549cdf3c410e73eed068dbf Mon Sep 17 00:00:00 2001 From: "Jacob Vosmaer (GitLab)" Date: Mon, 26 Feb 2018 09:54:20 +0000 Subject: Restart Unicorn and Sidekiq when GRPC throws 14:Endpoint read failed --- lib/gitlab/gitaly_client.rb | 23 +++++ lib/gitlab/sidekiq_middleware/memory_killer.rb | 67 ------------- lib/gitlab/sidekiq_middleware/shutdown.rb | 133 +++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 67 deletions(-) delete mode 100644 lib/gitlab/sidekiq_middleware/memory_killer.rb create mode 100644 lib/gitlab/sidekiq_middleware/shutdown.rb (limited to 'lib') diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb index c5d3e944f7d..9cd76630484 100644 --- a/lib/gitlab/gitaly_client.rb +++ b/lib/gitlab/gitaly_client.rb @@ -125,6 +125,8 @@ module Gitlab kwargs = yield(kwargs) if block_given? stub(service, storage).__send__(rpc, request, kwargs) # rubocop:disable GitlabSecurity/PublicSend + rescue GRPC::Unavailable => ex + handle_grpc_unavailable!(ex) ensure duration = Gitlab::Metrics::System.monotonic_time - start @@ -135,6 +137,27 @@ module Gitlab duration) end + def self.handle_grpc_unavailable!(ex) + status = ex.to_status + raise ex unless status.details == 'Endpoint read failed' + + # There is a bug in grpc 1.8.x that causes a client process to get stuck + # always raising '14:Endpoint read failed'. The only thing that we can + # do to recover is to restart the process. + # + # See https://gitlab.com/gitlab-org/gitaly/issues/1029 + + if Sidekiq.server? + raise Gitlab::SidekiqMiddleware::Shutdown::WantShutdown.new(ex.to_s) + else + # SIGQUIT requests a Unicorn worker to shut down gracefully after the current request. + Process.kill('QUIT', Process.pid) + end + + raise ex + end + private_class_method :handle_grpc_unavailable! + def self.current_transaction_labels Gitlab::Metrics::Transaction.current&.labels || {} end diff --git a/lib/gitlab/sidekiq_middleware/memory_killer.rb b/lib/gitlab/sidekiq_middleware/memory_killer.rb deleted file mode 100644 index b89ae2505c9..00000000000 --- a/lib/gitlab/sidekiq_middleware/memory_killer.rb +++ /dev/null @@ -1,67 +0,0 @@ -module Gitlab - module SidekiqMiddleware - class MemoryKiller - # Default the RSS limit to 0, meaning the MemoryKiller is disabled - MAX_RSS = (ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS'] || 0).to_s.to_i - # Give Sidekiq 15 minutes of grace time after exceeding the RSS limit - GRACE_TIME = (ENV['SIDEKIQ_MEMORY_KILLER_GRACE_TIME'] || 15 * 60).to_s.to_i - # Wait 30 seconds for running jobs to finish during graceful shutdown - SHUTDOWN_WAIT = (ENV['SIDEKIQ_MEMORY_KILLER_SHUTDOWN_WAIT'] || 30).to_s.to_i - - # Create a mutex used to ensure there will be only one thread waiting to - # shut Sidekiq down - MUTEX = Mutex.new - - def call(worker, job, queue) - yield - - current_rss = get_rss - - return unless MAX_RSS > 0 && current_rss > MAX_RSS - - Thread.new do - # Return if another thread is already waiting to shut Sidekiq down - return unless MUTEX.try_lock - - Sidekiq.logger.warn "Sidekiq worker PID-#{pid} current RSS #{current_rss}"\ - " exceeds maximum RSS #{MAX_RSS} after finishing job #{worker.class} JID-#{job['jid']}" - Sidekiq.logger.warn "Sidekiq worker PID-#{pid} will stop fetching new jobs in #{GRACE_TIME} seconds, and will be shut down #{SHUTDOWN_WAIT} seconds later" - - # Wait `GRACE_TIME` to give the memory intensive job time to finish. - # Then, tell Sidekiq to stop fetching new jobs. - wait_and_signal(GRACE_TIME, 'SIGSTP', 'stop fetching new jobs') - - # Wait `SHUTDOWN_WAIT` to give already fetched jobs time to finish. - # Then, tell Sidekiq to gracefully shut down by giving jobs a few more - # moments to finish, killing and requeuing them if they didn't, and - # then terminating itself. - wait_and_signal(SHUTDOWN_WAIT, 'SIGTERM', 'gracefully shut down') - - # Wait for Sidekiq to shutdown gracefully, and kill it if it didn't. - wait_and_signal(Sidekiq.options[:timeout] + 2, 'SIGKILL', 'die') - end - end - - private - - def get_rss - output, status = Gitlab::Popen.popen(%W(ps -o rss= -p #{pid}), Rails.root.to_s) - return 0 unless status.zero? - - output.to_i - end - - def wait_and_signal(time, signal, explanation) - Sidekiq.logger.warn "waiting #{time} seconds before sending Sidekiq worker PID-#{pid} #{signal} (#{explanation})" - sleep(time) - - Sidekiq.logger.warn "sending Sidekiq worker PID-#{pid} #{signal} (#{explanation})" - Process.kill(signal, pid) - end - - def pid - Process.pid - end - end - end -end diff --git a/lib/gitlab/sidekiq_middleware/shutdown.rb b/lib/gitlab/sidekiq_middleware/shutdown.rb new file mode 100644 index 00000000000..c2b8d6de66e --- /dev/null +++ b/lib/gitlab/sidekiq_middleware/shutdown.rb @@ -0,0 +1,133 @@ +require 'mutex_m' + +module Gitlab + module SidekiqMiddleware + class Shutdown + extend Mutex_m + + # Default the RSS limit to 0, meaning the MemoryKiller is disabled + MAX_RSS = (ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS'] || 0).to_s.to_i + # Give Sidekiq 15 minutes of grace time after exceeding the RSS limit + GRACE_TIME = (ENV['SIDEKIQ_MEMORY_KILLER_GRACE_TIME'] || 15 * 60).to_s.to_i + # Wait 30 seconds for running jobs to finish during graceful shutdown + SHUTDOWN_WAIT = (ENV['SIDEKIQ_MEMORY_KILLER_SHUTDOWN_WAIT'] || 30).to_s.to_i + + # This exception can be used to request that the middleware start shutting down Sidekiq + WantShutdown = Class.new(StandardError) + + ShutdownWithoutRaise = Class.new(WantShutdown) + private_constant :ShutdownWithoutRaise + + # For testing only, to avoid race conditions (?) in Rspec mocks. + attr_reader :trace + + # We store the shutdown thread in a class variable to ensure that there + # can be only one shutdown thread in the process. + def self.create_shutdown_thread + mu_synchronize do + return unless @shutdown_thread.nil? + + @shutdown_thread = Thread.new { yield } + end + end + + # For testing only: so we can wait for the shutdown thread to finish. + def self.shutdown_thread + mu_synchronize { @shutdown_thread } + end + + # For testing only: so that we can reset the global state before each test. + def self.clear_shutdown_thread + mu_synchronize { @shutdown_thread = nil } + end + + def initialize + @trace = Queue.new if Rails.env.test? + end + + def call(worker, job, queue) + shutdown_exception = nil + + begin + yield + check_rss! + rescue WantShutdown => ex + shutdown_exception = ex + end + + return unless shutdown_exception + + self.class.create_shutdown_thread do + do_shutdown(worker, job, shutdown_exception) + end + + raise shutdown_exception unless shutdown_exception.is_a?(ShutdownWithoutRaise) + end + + private + + def do_shutdown(worker, job, shutdown_exception) + Sidekiq.logger.warn "Sidekiq worker PID-#{pid} shutting down because of #{shutdown_exception} after job "\ + "#{worker.class} JID-#{job['jid']}" + Sidekiq.logger.warn "Sidekiq worker PID-#{pid} will stop fetching new jobs in #{GRACE_TIME} seconds, and will be shut down #{SHUTDOWN_WAIT} seconds later" + + # Wait `GRACE_TIME` to give the memory intensive job time to finish. + # Then, tell Sidekiq to stop fetching new jobs. + wait_and_signal(GRACE_TIME, 'SIGTSTP', 'stop fetching new jobs') + + # Wait `SHUTDOWN_WAIT` to give already fetched jobs time to finish. + # Then, tell Sidekiq to gracefully shut down by giving jobs a few more + # moments to finish, killing and requeuing them if they didn't, and + # then terminating itself. + wait_and_signal(SHUTDOWN_WAIT, 'SIGTERM', 'gracefully shut down') + + # Wait for Sidekiq to shutdown gracefully, and kill it if it didn't. + wait_and_signal(Sidekiq.options[:timeout] + 2, 'SIGKILL', 'die') + end + + def check_rss! + return unless MAX_RSS > 0 + + current_rss = get_rss + return unless current_rss > MAX_RSS + + raise ShutdownWithoutRaise.new("current RSS #{current_rss} exceeds maximum RSS #{MAX_RSS}") + end + + def get_rss + output, status = Gitlab::Popen.popen(%W(ps -o rss= -p #{pid}), Rails.root.to_s) + return 0 unless status.zero? + + output.to_i + end + + def wait_and_signal(time, signal, explanation) + Sidekiq.logger.warn "waiting #{time} seconds before sending Sidekiq worker PID-#{pid} #{signal} (#{explanation})" + sleep(time) + + Sidekiq.logger.warn "sending Sidekiq worker PID-#{pid} #{signal} (#{explanation})" + kill(signal, pid) + end + + def pid + Process.pid + end + + def sleep(time) + if Rails.env.test? + @trace << [:sleep, time] + else + Kernel.sleep(time) + end + end + + def kill(signal, pid) + if Rails.env.test? + @trace << [:kill, signal, pid] + else + Process.kill(signal, pid) + end + end + end + end +end -- cgit v1.2.1 From 1751cab41fb48fb4c231bfea9f3ab334ba98fea5 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 26 Feb 2018 12:17:50 +0100 Subject: Extract WaitableWorker out of AuthorizedProjectsWorker --- lib/gitlab/job_waiter.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/gitlab/job_waiter.rb b/lib/gitlab/job_waiter.rb index f654508c391..f7a8eae0be4 100644 --- a/lib/gitlab/job_waiter.rb +++ b/lib/gitlab/job_waiter.rb @@ -15,16 +15,22 @@ module Gitlab # push to that array when done. Once the waiter has popped `count` items, it # knows all the jobs are done. class JobWaiter + KEY_PREFIX = "gitlab:job_waiter".freeze + def self.notify(key, jid) Gitlab::Redis::SharedState.with { |redis| redis.lpush(key, jid) } end + def self.key?(key) + key.is_a?(String) && key =~ /\A#{KEY_PREFIX}:\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/ + end + attr_reader :key, :finished attr_accessor :jobs_remaining # jobs_remaining - the number of jobs left to wait for # key - The key of this waiter. - def initialize(jobs_remaining = 0, key = "gitlab:job_waiter:#{SecureRandom.uuid}") + def initialize(jobs_remaining = 0, key = "#{KEY_PREFIX}:#{SecureRandom.uuid}") @key = key @jobs_remaining = jobs_remaining @finished = [] -- cgit v1.2.1 From c370f53cb68038b469ec219cf2ec248e62a72683 Mon Sep 17 00:00:00 2001 From: Ahmad Sherif Date: Fri, 16 Feb 2018 21:39:43 +0100 Subject: Migrate recursive tree entries fetching to Gitaly --- lib/gitlab/git/tree.rb | 23 +++++++++++++++++++---- lib/gitlab/gitaly_client/commit_service.rb | 5 +++-- 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/gitlab/git/tree.rb b/lib/gitlab/git/tree.rb index ba6058fd3c9..b6ceb542dd1 100644 --- a/lib/gitlab/git/tree.rb +++ b/lib/gitlab/git/tree.rb @@ -14,14 +14,14 @@ module Gitlab # Uses rugged for raw objects # # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/320 - def where(repository, sha, path = nil) + def where(repository, sha, path = nil, recursive = false) path = nil if path == '' || path == '/' Gitlab::GitalyClient.migrate(:tree_entries) do |is_enabled| if is_enabled - repository.gitaly_commit_client.tree_entries(repository, sha, path) + repository.gitaly_commit_client.tree_entries(repository, sha, path, recursive) else - tree_entries_from_rugged(repository, sha, path) + tree_entries_from_rugged(repository, sha, path, recursive) end end end @@ -57,7 +57,22 @@ module Gitlab end end - def tree_entries_from_rugged(repository, sha, path) + def tree_entries_from_rugged(repository, sha, path, recursive) + current_path_entries = get_tree_entries_from_rugged(repository, sha, path) + ordered_entries = [] + + current_path_entries.each do |entry| + ordered_entries << entry + + if recursive && entry.dir? + ordered_entries.concat(tree_entries_from_rugged(repository, sha, entry.path, true)) + end + end + + ordered_entries + end + + def get_tree_entries_from_rugged(repository, sha, path) commit = repository.lookup(sha) root_tree = commit.tree diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb index 269a048cf5d..d60f57717b5 100644 --- a/lib/gitlab/gitaly_client/commit_service.rb +++ b/lib/gitlab/gitaly_client/commit_service.rb @@ -105,11 +105,12 @@ module Gitlab entry unless entry.oid.blank? end - def tree_entries(repository, revision, path) + def tree_entries(repository, revision, path, recursive) request = Gitaly::GetTreeEntriesRequest.new( repository: @gitaly_repo, revision: encode_binary(revision), - path: path.present? ? encode_binary(path) : '.' + path: path.present? ? encode_binary(path) : '.', + recursive: recursive ) response = GitalyClient.call(@repository.storage, :commit_service, :get_tree_entries, request, timeout: GitalyClient.medium_timeout) -- cgit v1.2.1