summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/api/api_guard.rb8
-rw-r--r--lib/api/entities.rb20
-rw-r--r--lib/api/groups.rb66
-rw-r--r--lib/api/helpers.rb9
-rw-r--r--lib/api/pages_domains.rb22
-rw-r--r--lib/gitlab/git/operation_service.rb10
-rw-r--r--lib/gitlab/git/remote_repository.rb82
-rw-r--r--lib/gitlab/git/repository.rb36
-rw-r--r--lib/gitlab/gon_helper.rb2
-rw-r--r--lib/gitlab/hook_data/issue_builder.rb1
-rw-r--r--lib/gitlab/utils/strong_memoize.rb31
11 files changed, 227 insertions, 60 deletions
diff --git a/lib/api/api_guard.rb b/lib/api/api_guard.rb
index b9c7d443f6c..c1c0d344917 100644
--- a/lib/api/api_guard.rb
+++ b/lib/api/api_guard.rb
@@ -42,6 +42,8 @@ module API
# Helper Methods for Grape Endpoint
module HelperMethods
+ include Gitlab::Utils::StrongMemoize
+
def find_current_user!
user = find_user_from_access_token || find_user_from_warden
return unless user
@@ -52,9 +54,9 @@ module API
end
def access_token
- return @access_token if defined?(@access_token)
-
- @access_token = find_oauth_access_token || find_personal_access_token
+ strong_memoize(:access_token) do
+ find_oauth_access_token || find_personal_access_token
+ end
end
def validate_access_token!(scopes: [])
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index a382db92e8d..16ae99b5c6c 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1042,6 +1042,11 @@ module API
expose :value
end
+ class PagesDomainCertificateExpiration < Grape::Entity
+ expose :expired?, as: :expired
+ expose :expiration
+ end
+
class PagesDomainCertificate < Grape::Entity
expose :subject
expose :expired?, as: :expired
@@ -1049,12 +1054,23 @@ module API
expose :certificate_text
end
+ class PagesDomainBasic < Grape::Entity
+ expose :domain
+ expose :url
+ expose :certificate,
+ as: :certificate_expiration,
+ if: ->(pages_domain, _) { pages_domain.certificate? },
+ using: PagesDomainCertificateExpiration do |pages_domain|
+ pages_domain
+ end
+ end
+
class PagesDomain < Grape::Entity
expose :domain
expose :url
expose :certificate,
- if: ->(pages_domain, _) { pages_domain.certificate? },
- using: PagesDomainCertificate do |pages_domain|
+ if: ->(pages_domain, _) { pages_domain.certificate? },
+ using: PagesDomainCertificate do |pages_domain|
pages_domain
end
end
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 340a7cecf09..bcf2e6dae1d 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -25,24 +25,7 @@ module API
optional :statistics, type: Boolean, default: false, desc: 'Include project statistics'
end
- def present_groups(groups, options = {})
- options = options.reverse_merge(
- with: Entities::Group,
- current_user: current_user
- )
-
- groups = groups.with_statistics if options[:statistics]
- present paginate(groups), options
- end
- end
-
- resource :groups do
- include CustomAttributesEndpoints
-
- desc 'Get a groups list' do
- success Entities::Group
- end
- params do
+ params :group_list_params do
use :statistics_params
optional :skip_groups, type: Array[Integer], desc: 'Array of group ids to exclude from list'
optional :all_available, type: Boolean, desc: 'Show all group that you have access to'
@@ -52,19 +35,47 @@ module API
optional :sort, type: String, values: %w[asc desc], default: 'asc', desc: 'Sort by asc (ascending) or desc (descending)'
use :pagination
end
- get do
+
+ def find_groups(params)
find_params = {
all_available: params[:all_available],
- owned: params[:owned],
- custom_attributes: params[:custom_attributes]
+ custom_attributes: params[:custom_attributes],
+ owned: params[:owned]
}
+ find_params[:parent] = find_group!(params[:id]) if params[:id]
groups = GroupsFinder.new(current_user, find_params).execute
groups = groups.search(params[:search]) if params[:search].present?
groups = groups.where.not(id: params[:skip_groups]) if params[:skip_groups].present?
groups = groups.reorder(params[:order_by] => params[:sort])
- present_groups groups, statistics: params[:statistics] && current_user.admin?
+ groups
+ end
+
+ def present_groups(params, groups)
+ options = {
+ with: Entities::Group,
+ current_user: current_user,
+ statistics: params[:statistics] && current_user.admin?
+ }
+
+ groups = groups.with_statistics if options[:statistics]
+ present paginate(groups), options
+ end
+ end
+
+ resource :groups do
+ include CustomAttributesEndpoints
+
+ desc 'Get a groups list' do
+ success Entities::Group
+ end
+ params do
+ use :group_list_params
+ end
+ get do
+ groups = find_groups(params)
+ present_groups params, groups
end
desc 'Create a group. Available only for users who can create groups.' do
@@ -166,6 +177,17 @@ module API
present paginate(projects), with: entity, current_user: current_user
end
+ desc 'Get a list of subgroups in this group.' do
+ success Entities::Group
+ end
+ params do
+ use :group_list_params
+ end
+ get ":id/subgroups" do
+ groups = find_groups(params)
+ present_groups params, groups
+ end
+
desc 'Transfer a project to the group namespace. Available only for admin.' do
success Entities::GroupDetail
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 5f9b94cc89c..3c8960cb1ab 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -155,6 +155,11 @@ module API
end
end
+ def authenticated_with_full_private_access!
+ authenticate!
+ forbidden! unless current_user.full_private_access?
+ end
+
def authenticated_as_admin!
authenticate!
forbidden! unless current_user.admin?
@@ -190,6 +195,10 @@ module API
not_found! unless user_project.pages_available?
end
+ def require_pages_config_enabled!
+ not_found! unless Gitlab.config.pages.enabled
+ end
+
def can?(object, action, subject = :global)
Ability.allowed?(object, action, subject)
end
diff --git a/lib/api/pages_domains.rb b/lib/api/pages_domains.rb
index 259f3f34068..d7b613a717e 100644
--- a/lib/api/pages_domains.rb
+++ b/lib/api/pages_domains.rb
@@ -4,7 +4,6 @@ module API
before do
authenticate!
- require_pages_enabled!
end
after_validation do
@@ -29,10 +28,31 @@ module API
end
end
+ resource :pages do
+ before do
+ require_pages_config_enabled!
+ authenticated_with_full_private_access!
+ end
+
+ desc "Get all pages domains" do
+ success Entities::PagesDomainBasic
+ end
+ params do
+ use :pagination
+ end
+ get "domains" do
+ present paginate(PagesDomain.all), with: Entities::PagesDomainBasic
+ end
+ end
+
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: { id: %r{[^/]+} } do
+ before do
+ require_pages_enabled!
+ end
+
desc 'Get all pages domains' do
success Entities::PagesDomain
end
diff --git a/lib/gitlab/git/operation_service.rb b/lib/gitlab/git/operation_service.rb
index ab94ba8a73a..e36d5410431 100644
--- a/lib/gitlab/git/operation_service.rb
+++ b/lib/gitlab/git/operation_service.rb
@@ -72,7 +72,7 @@ module Gitlab
# Whenever `start_branch_name` is passed, if `branch_name` doesn't exist,
# it would be created from `start_branch_name`.
- # If `start_project` is passed, and the branch doesn't exist,
+ # If `start_repository` is passed, and the branch doesn't exist,
# it would try to find the commits from it instead of current repository.
def with_branch(
branch_name,
@@ -80,15 +80,13 @@ module Gitlab
start_repository: repository,
&block)
- # Refactoring aid
- unless start_repository.is_a?(Gitlab::Git::Repository)
- raise "expected a Gitlab::Git::Repository, got #{start_repository}"
- end
+ Gitlab::Git.check_namespace!(start_repository)
+ start_repository = RemoteRepository.new(start_repository) unless start_repository.is_a?(RemoteRepository)
start_branch_name = nil if start_repository.empty_repo?
if start_branch_name && !start_repository.branch_exists?(start_branch_name)
- raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.full_path}"
+ raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.relative_path}"
end
update_branch_with_hooks(branch_name) do
diff --git a/lib/gitlab/git/remote_repository.rb b/lib/gitlab/git/remote_repository.rb
new file mode 100644
index 00000000000..3685aa20669
--- /dev/null
+++ b/lib/gitlab/git/remote_repository.rb
@@ -0,0 +1,82 @@
+module Gitlab
+ module Git
+ #
+ # When a Gitaly call involves two repositories instead of one we cannot
+ # assume that both repositories are on the same Gitaly server. In this
+ # case we need to make a distinction between the repository that the
+ # call is being made on (a Repository instance), and the "other"
+ # repository (a RemoteRepository instance). This is the reason why we
+ # have the RemoteRepository class in Gitlab::Git.
+ #
+ # When you make changes, be aware that gitaly-ruby sub-classes this
+ # class.
+ #
+ class RemoteRepository
+ attr_reader :path, :relative_path, :gitaly_repository
+
+ def initialize(repository)
+ @relative_path = repository.relative_path
+ @gitaly_repository = repository.gitaly_repository
+
+ # These instance variables will not be available in gitaly-ruby, where
+ # we have no disk access to this repository.
+ @repository = repository
+ @path = repository.path
+ end
+
+ def empty_repo?
+ # We will override this implementation in gitaly-ruby because we cannot
+ # use '@repository' there.
+ @repository.empty_repo?
+ end
+
+ def commit_id(revision)
+ # We will override this implementation in gitaly-ruby because we cannot
+ # use '@repository' there.
+ @repository.commit(revision)&.sha
+ end
+
+ def branch_exists?(name)
+ # We will override this implementation in gitaly-ruby because we cannot
+ # use '@repository' there.
+ @repository.branch_exists?(name)
+ end
+
+ # Compares self to a Gitlab::Git::Repository. This implementation uses
+ # 'self.gitaly_repository' so that it will also work in the
+ # GitalyRemoteRepository subclass defined in gitaly-ruby.
+ def same_repository?(other_repository)
+ gitaly_repository.storage_name == other_repository.storage &&
+ gitaly_repository.relative_path == other_repository.relative_path
+ end
+
+ def fetch_env
+ gitaly_ssh = File.absolute_path(File.join(Gitlab.config.gitaly.client_path, 'gitaly-ssh'))
+ gitaly_address = gitaly_client.address(storage)
+ gitaly_token = gitaly_client.token(storage)
+
+ request = Gitaly::SSHUploadPackRequest.new(repository: gitaly_repository)
+ env = {
+ 'GITALY_ADDRESS' => gitaly_address,
+ 'GITALY_PAYLOAD' => request.to_json,
+ 'GITALY_WD' => Dir.pwd,
+ 'GIT_SSH_COMMAND' => "#{gitaly_ssh} upload-pack"
+ }
+ env['GITALY_TOKEN'] = gitaly_token if gitaly_token.present?
+
+ env
+ end
+
+ private
+
+ # Must return an object that responds to 'address' and 'storage'.
+ def gitaly_client
+ Gitlab::GitalyClient
+ end
+
+ def storage
+ gitaly_repository.storage_name
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index d236e1b03e6..cfb88a0c12b 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -58,7 +58,7 @@ module Gitlab
# Rugged repo object
attr_reader :rugged
- attr_reader :storage, :gl_repository, :relative_path, :gitaly_resolver
+ attr_reader :storage, :gl_repository, :relative_path
# This initializer method is only used on the client side (gitlab-ce).
# Gitaly-ruby uses a different initializer.
@@ -66,7 +66,6 @@ module Gitlab
@storage = storage
@relative_path = relative_path
@gl_repository = gl_repository
- @gitaly_resolver = Gitlab::GitalyClient
storage_path = Gitlab.config.repositories.storages[@storage]['path']
@path = File.join(storage_path, @relative_path)
@@ -105,7 +104,7 @@ module Gitlab
end
def exists?
- Gitlab::GitalyClient.migrate(:repository_exists) do |enabled|
+ Gitlab::GitalyClient.migrate(:repository_exists, status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |enabled|
if enabled
gitaly_repository_client.exists?
else
@@ -1014,23 +1013,22 @@ module Gitlab
def with_repo_branch_commit(start_repository, start_branch_name)
Gitlab::Git.check_namespace!(start_repository)
+ start_repository = RemoteRepository.new(start_repository) unless start_repository.is_a?(RemoteRepository)
return yield nil if start_repository.empty_repo?
- if start_repository == self
+ if start_repository.same_repository?(self)
yield commit(start_branch_name)
else
- start_commit = start_repository.commit(start_branch_name)
+ start_commit_id = start_repository.commit_id(start_branch_name)
- return yield nil unless start_commit
+ return yield nil unless start_commit_id
- sha = start_commit.sha
-
- if branch_commit = commit(sha)
+ if branch_commit = commit(start_commit_id)
yield branch_commit
else
with_repo_tmp_commit(
- start_repository, start_branch_name, sha) do |tmp_commit|
+ start_repository, start_branch_name, start_commit_id) do |tmp_commit|
yield tmp_commit
end
end
@@ -1087,6 +1085,9 @@ module Gitlab
end
def fetch_ref(source_repository, source_ref:, target_ref:)
+ Gitlab::Git.check_namespace!(source_repository)
+ source_repository = RemoteRepository.new(source_repository) unless source_repository.is_a?(RemoteRepository)
+
message, status = GitalyClient.migrate(:fetch_ref) do |is_enabled|
if is_enabled
gitaly_fetch_ref(source_repository, source_ref: source_ref, target_ref: target_ref)
@@ -1620,22 +1621,9 @@ module Gitlab
end
def gitaly_fetch_ref(source_repository, source_ref:, target_ref:)
- gitaly_ssh = File.absolute_path(File.join(Gitlab.config.gitaly.client_path, 'gitaly-ssh'))
- gitaly_address = gitaly_resolver.address(source_repository.storage)
- gitaly_token = gitaly_resolver.token(source_repository.storage)
-
- request = Gitaly::SSHUploadPackRequest.new(repository: source_repository.gitaly_repository)
- env = {
- 'GITALY_ADDRESS' => gitaly_address,
- 'GITALY_PAYLOAD' => request.to_json,
- 'GITALY_WD' => Dir.pwd,
- 'GIT_SSH_COMMAND' => "#{gitaly_ssh} upload-pack"
- }
- env['GITALY_TOKEN'] = gitaly_token if gitaly_token.present?
-
args = %W(fetch --no-tags -f ssh://gitaly/internal.git #{source_ref}:#{target_ref})
- run_git(args, env: env)
+ run_git(args, env: source_repository.fetch_env)
end
def gitaly_ff_merge(user, source_sha, target_branch)
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 3a666c2268b..dfcdfc307b6 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -20,7 +20,7 @@ module Gitlab
gon.gitlab_url = Gitlab.config.gitlab.url
gon.revision = Gitlab::REVISION
gon.gitlab_logo = ActionController::Base.helpers.asset_path('gitlab_logo.png')
- gon.sprite_icons = ActionController::Base.helpers.asset_path('icons.svg')
+ gon.sprite_icons = IconsHelper.sprite_icon_path
if current_user
gon.current_user_id = current_user.id
diff --git a/lib/gitlab/hook_data/issue_builder.rb b/lib/gitlab/hook_data/issue_builder.rb
index de9cab80a02..196f2b6b34c 100644
--- a/lib/gitlab/hook_data/issue_builder.rb
+++ b/lib/gitlab/hook_data/issue_builder.rb
@@ -4,7 +4,6 @@ module Gitlab
SAFE_HOOK_ATTRIBUTES = %i[
assignee_id
author_id
- branch_name
closed_at
confidential
created_at
diff --git a/lib/gitlab/utils/strong_memoize.rb b/lib/gitlab/utils/strong_memoize.rb
new file mode 100644
index 00000000000..a2ac9285b56
--- /dev/null
+++ b/lib/gitlab/utils/strong_memoize.rb
@@ -0,0 +1,31 @@
+module Gitlab
+ module Utils
+ module StrongMemoize
+ # Instead of writing patterns like this:
+ #
+ # def trigger_from_token
+ # return @trigger if defined?(@trigger)
+ #
+ # @trigger = Ci::Trigger.find_by_token(params[:token].to_s)
+ # end
+ #
+ # We could write it like:
+ #
+ # def trigger_from_token
+ # strong_memoize(:trigger) do
+ # Ci::Trigger.find_by_token(params[:token].to_s)
+ # end
+ # end
+ #
+ def strong_memoize(name)
+ ivar_name = "@#{name}"
+
+ if instance_variable_defined?(ivar_name)
+ instance_variable_get(ivar_name)
+ else
+ instance_variable_set(ivar_name, yield)
+ end
+ end
+ end
+ end
+end