summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMatija Čupić <matteeyah@gmail.com>2018-01-05 20:04:33 +0100
committerMatija Čupić <matteeyah@gmail.com>2018-01-05 20:04:33 +0100
commitb058af1be6aad166fbab2809bb8430bc90b4896f (patch)
tree6266e653a231e19a966693a7c1da7e07f6019978 /lib
parent12984a73029408ef4ca10446131613e9ac371eb9 (diff)
parent3d162d192ba2a57776de62b553a2a0a9a9245f8a (diff)
downloadgitlab-ce-b058af1be6aad166fbab2809bb8430bc90b4896f.tar.gz
Merge branch 'master' into 39957-redirect-to-gpc-page-if-users-try-to-create-a-cluster-but-the-account-is-not-enabled
Diffstat (limited to 'lib')
-rw-r--r--lib/api/api.rb4
-rw-r--r--lib/api/boards.rb84
-rw-r--r--lib/api/boards_responses.rb50
-rw-r--r--lib/api/entities.rb5
-rw-r--r--lib/api/helpers.rb15
-rw-r--r--lib/api/issues.rb13
-rw-r--r--lib/api/labels.rb4
-rw-r--r--lib/api/merge_requests.rb10
-rw-r--r--lib/api/v3/labels.rb2
-rw-r--r--lib/banzai/filter/mermaid_filter.rb11
-rw-r--r--lib/gitlab/encoding_helper.rb26
-rw-r--r--lib/gitlab/git.rb2
-rw-r--r--lib/gitlab/git/blob.rb31
-rw-r--r--lib/gitlab/git/operation_service.rb5
-rw-r--r--lib/gitlab/git/repository.rb84
-rw-r--r--lib/gitlab/import_export/command_line_util.rb5
-rw-r--r--lib/gitlab/import_export/repo_restorer.rb2
-rw-r--r--lib/gitlab/ldap/adapter.rb2
-rw-r--r--lib/gitlab/ldap/config.rb2
-rw-r--r--lib/gitlab/ldap/person.rb36
-rw-r--r--lib/gitlab/setup_helper.rb61
-rw-r--r--lib/gitlab/shell.rb17
-rw-r--r--lib/tasks/gitlab/check.rake41
-rw-r--r--lib/tasks/gitlab/git.rake35
-rw-r--r--lib/tasks/gitlab/gitaly.rake57
-rw-r--r--lib/tasks/gitlab/task_helpers.rb2
26 files changed, 398 insertions, 208 deletions
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 8094597d238..e0d14281c96 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -119,6 +119,7 @@ module API
mount ::API::Features
mount ::API::Files
mount ::API::Groups
+ mount ::API::GroupMilestones
mount ::API::Internal
mount ::API::Issues
mount ::API::Jobs
@@ -129,8 +130,6 @@ module API
mount ::API::Members
mount ::API::MergeRequestDiffs
mount ::API::MergeRequests
- mount ::API::ProjectMilestones
- mount ::API::GroupMilestones
mount ::API::Namespaces
mount ::API::Notes
mount ::API::NotificationSettings
@@ -139,6 +138,7 @@ module API
mount ::API::PipelineSchedules
mount ::API::ProjectHooks
mount ::API::Projects
+ mount ::API::ProjectMilestones
mount ::API::ProjectSnippets
mount ::API::ProtectedBranches
mount ::API::Repositories
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index 366b0dc9a6f..6c706b2b4e1 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -1,45 +1,46 @@
module API
class Boards < Grape::API
+ include BoardsResponses
include PaginationParams
before { authenticate! }
+ helpers do
+ def board_parent
+ user_project
+ end
+ end
+
params do
requires :id, type: String, desc: 'The ID of a project'
end
resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
- desc 'Get all project boards' do
- detail 'This feature was introduced in 8.13'
- success Entities::Board
- end
- params do
- use :pagination
- end
- get ':id/boards' do
- authorize!(:read_board, user_project)
- present paginate(user_project.boards), with: Entities::Board
+ segment ':id/boards' do
+ desc 'Get all project boards' do
+ detail 'This feature was introduced in 8.13'
+ success Entities::Board
+ end
+ params do
+ use :pagination
+ end
+ get '/' do
+ authorize!(:read_board, user_project)
+ present paginate(board_parent.boards), with: Entities::Board
+ end
+
+ desc 'Find a project board' do
+ detail 'This feature was introduced in 10.4'
+ success Entities::Board
+ end
+ get '/:board_id' do
+ present board, with: Entities::Board
+ end
end
params do
requires :board_id, type: Integer, desc: 'The ID of a board'
end
segment ':id/boards/:board_id' do
- helpers do
- def project_board
- board = user_project.boards.first
-
- if params[:board_id] == board.id
- board
- else
- not_found!('Board')
- end
- end
-
- def board_lists
- project_board.lists.destroyable
- end
- end
-
desc 'Get the lists of a project board' do
detail 'Does not include `done` list. This feature was introduced in 8.13'
success Entities::List
@@ -72,22 +73,13 @@ module API
requires :label_id, type: Integer, desc: 'The ID of an existing label'
end
post '/lists' do
- unless available_labels.exists?(params[:label_id])
+ unless available_labels_for(user_project).exists?(params[:label_id])
render_api_error!({ error: 'Label not found!' }, 400)
end
authorize!(:admin_list, user_project)
- service = ::Boards::Lists::CreateService.new(user_project, current_user,
- { label_id: params[:label_id] })
-
- list = service.execute(project_board)
-
- if list.valid?
- present list, with: Entities::List
- else
- render_validation_error!(list)
- end
+ create_list
end
desc 'Moves a board list to a new position' do
@@ -99,18 +91,11 @@ module API
requires :position, type: Integer, desc: 'The position of the list'
end
put '/lists/:list_id' do
- list = project_board.lists.movable.find(params[:list_id])
+ list = board_lists.find(params[:list_id])
authorize!(:admin_list, user_project)
- service = ::Boards::Lists::MoveService.new(user_project, current_user,
- { position: params[:position] })
-
- if service.execute(list)
- present list, with: Entities::List
- else
- render_api_error!({ error: "List could not be moved!" }, 400)
- end
+ move_list(list)
end
desc 'Delete a board list' do
@@ -124,12 +109,7 @@ module API
authorize!(:admin_list, user_project)
list = board_lists.find(params[:list_id])
- destroy_conditionally!(list) do |list|
- service = ::Boards::Lists::DestroyService.new(user_project, current_user)
- unless service.execute(list)
- render_api_error!({ error: 'List could not be deleted!' }, 400)
- end
- end
+ destroy_list(list)
end
end
end
diff --git a/lib/api/boards_responses.rb b/lib/api/boards_responses.rb
new file mode 100644
index 00000000000..ead0943a74d
--- /dev/null
+++ b/lib/api/boards_responses.rb
@@ -0,0 +1,50 @@
+module API
+ module BoardsResponses
+ extend ActiveSupport::Concern
+
+ included do
+ helpers do
+ def board
+ board_parent.boards.find(params[:board_id])
+ end
+
+ def board_lists
+ board.lists.destroyable
+ end
+
+ def create_list
+ create_list_service =
+ ::Boards::Lists::CreateService.new(board_parent, current_user, { label_id: params[:label_id] })
+
+ list = create_list_service.execute(board)
+
+ if list.valid?
+ present list, with: Entities::List
+ else
+ render_validation_error!(list)
+ end
+ end
+
+ def move_list(list)
+ move_list_service =
+ ::Boards::Lists::MoveService.new(board_parent, current_user, { position: params[:position].to_i })
+
+ if move_list_service.execute(list)
+ present list, with: Entities::List
+ else
+ render_api_error!({ error: "List could not be moved!" }, 400)
+ end
+ end
+
+ def destroy_list(list)
+ destroy_conditionally!(list) do |list|
+ service = ::Boards::Lists::DestroyService.new(board_parent, current_user)
+ unless service.execute(list)
+ render_api_error!({ error: 'List could not be deleted!' }, 400)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 4ad4a1f7867..bd0c54a1b04 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -791,6 +791,8 @@ module API
class Board < Grape::Entity
expose :id
+ expose :project, using: Entities::BasicProjectDetails
+
expose :lists, using: Entities::List do |board|
board.lists.destroyable
end
@@ -862,6 +864,8 @@ module API
expose :active
expose :is_shared
expose :name
+ expose :online?, as: :online
+ expose :status
end
class RunnerDetails < Runner
@@ -1133,6 +1137,7 @@ module API
class PagesDomainBasic < Grape::Entity
expose :domain
expose :url
+ expose :project_id
expose :certificate,
as: :certificate_expiration,
if: ->(pages_domain, _) { pages_domain.certificate? },
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 8ad4b2ecbf3..bf388163ec8 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -74,8 +74,15 @@ module API
page || not_found!('Wiki Page')
end
- def available_labels
- @available_labels ||= LabelsFinder.new(current_user, project_id: user_project.id).execute
+ def available_labels_for(label_parent)
+ search_params =
+ if label_parent.is_a?(Project)
+ { project_id: label_parent.id }
+ else
+ { group_id: label_parent.id, only_group_labels: true }
+ end
+
+ LabelsFinder.new(current_user, search_params).execute
end
def find_user(id)
@@ -141,7 +148,9 @@ module API
end
def find_project_label(id)
- label = available_labels.find_by_id(id) || available_labels.find_by_title(id)
+ labels = available_labels_for(user_project)
+ label = labels.find_by_id(id) || labels.find_by_title(id)
+
label || not_found!('Label')
end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index b29c5848aef..7aa10631d53 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -277,6 +277,19 @@ module API
present paginate(merge_requests), with: Entities::MergeRequestBasic, current_user: current_user, project: user_project
end
+ desc 'List participants for an issue' do
+ success Entities::UserBasic
+ end
+ params do
+ requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
+ end
+ get ':id/issues/:issue_iid/participants' do
+ issue = find_project_issue(params[:issue_iid])
+ participants = ::Kaminari.paginate_array(issue.participants)
+
+ present paginate(participants), with: Entities::UserBasic, current_user: current_user, project: user_project
+ end
+
desc 'Get the user agent details for an issue' do
success Entities::UserAgentDetail
end
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index e41a1720ac1..81eaf56e48e 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -15,7 +15,7 @@ module API
use :pagination
end
get ':id/labels' do
- present paginate(available_labels), with: Entities::Label, current_user: current_user, project: user_project
+ present paginate(available_labels_for(user_project)), with: Entities::Label, current_user: current_user, project: user_project
end
desc 'Create a new label' do
@@ -30,7 +30,7 @@ module API
post ':id/labels' do
authorize! :admin_label, user_project
- label = available_labels.find_by(title: params[:name])
+ label = available_labels_for(user_project).find_by(title: params[:name])
conflict!('Label already exists') if label
priority = params.delete(:priority)
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 02f2b75ab9d..8f665b39fa8 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -185,6 +185,16 @@ module API
present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project
end
+ desc 'Get the participants of a merge request' do
+ success Entities::UserBasic
+ end
+ get ':id/merge_requests/:merge_request_iid/participants' do
+ merge_request = find_merge_request_with_access(params[:merge_request_iid])
+ participants = ::Kaminari.paginate_array(merge_request.participants)
+
+ present paginate(participants), with: Entities::UserBasic
+ end
+
desc 'Get the commits of a merge request' do
success Entities::Commit
end
diff --git a/lib/api/v3/labels.rb b/lib/api/v3/labels.rb
index bd5eb2175e8..4157462ec2a 100644
--- a/lib/api/v3/labels.rb
+++ b/lib/api/v3/labels.rb
@@ -11,7 +11,7 @@ module API
success ::API::Entities::Label
end
get ':id/labels' do
- present available_labels, with: ::API::Entities::Label, current_user: current_user, project: user_project
+ present available_labels_for(user_project), with: ::API::Entities::Label, current_user: current_user, project: user_project
end
desc 'Delete an existing label' do
diff --git a/lib/banzai/filter/mermaid_filter.rb b/lib/banzai/filter/mermaid_filter.rb
index b545b947a2c..65c131e08d9 100644
--- a/lib/banzai/filter/mermaid_filter.rb
+++ b/lib/banzai/filter/mermaid_filter.rb
@@ -2,16 +2,7 @@ module Banzai
module Filter
class MermaidFilter < HTML::Pipeline::Filter
def call
- doc.css('pre[lang="mermaid"]').add_class('mermaid')
- doc.css('pre[lang="mermaid"]').add_class('js-render-mermaid')
-
- # The `<code></code>` blocks are added in the lib/banzai/filter/syntax_highlight_filter.rb
- # We want to keep context and consistency, so we the blocks are added for all filters.
- # Details: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15107/diffs?diff_id=7962900#note_45495859
- doc.css('pre[lang="mermaid"]').each do |pre|
- document = pre.at('code')
- document.replace(document.content)
- end
+ doc.css('pre[lang="mermaid"] > code').add_class('js-render-mermaid')
doc
end
diff --git a/lib/gitlab/encoding_helper.rb b/lib/gitlab/encoding_helper.rb
index 6b53eb4533d..c0edcabc6fd 100644
--- a/lib/gitlab/encoding_helper.rb
+++ b/lib/gitlab/encoding_helper.rb
@@ -14,14 +14,7 @@ module Gitlab
ENCODING_CONFIDENCE_THRESHOLD = 50
def encode!(message)
- return nil unless message.respond_to?(:force_encoding)
- return message if message.encoding == Encoding::UTF_8 && message.valid_encoding?
-
- if message.respond_to?(:frozen?) && message.frozen?
- message = message.dup
- end
-
- message.force_encoding("UTF-8")
+ message = force_encode_utf8(message)
return message if message.valid_encoding?
# return message if message type is binary
@@ -35,6 +28,8 @@ module Gitlab
# encode and clean the bad chars
message.replace clean(message)
+ rescue ArgumentError
+ return nil
rescue
encoding = detect ? detect[:encoding] : "unknown"
"--broken encoding: #{encoding}"
@@ -54,8 +49,8 @@ module Gitlab
end
def encode_utf8(message)
- return nil unless message.is_a?(String)
- return message if message.encoding == Encoding::UTF_8 && message.valid_encoding?
+ message = force_encode_utf8(message)
+ return message if message.valid_encoding?
detect = CharlockHolmes::EncodingDetector.detect(message)
if detect && detect[:encoding]
@@ -69,6 +64,8 @@ module Gitlab
else
clean(message)
end
+ rescue ArgumentError
+ return nil
end
def encode_binary(s)
@@ -83,6 +80,15 @@ module Gitlab
private
+ def force_encode_utf8(message)
+ raise ArgumentError unless message.respond_to?(:force_encoding)
+ return message if message.encoding == Encoding::UTF_8 && message.valid_encoding?
+
+ message = message.dup if message.respond_to?(:frozen?) && message.frozen?
+
+ message.force_encoding("UTF-8")
+ end
+
def clean(message)
message.encode("UTF-16BE", undef: :replace, invalid: :replace, replace: "")
.encode("UTF-8")
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index 1f7c35cafaa..71647099f83 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -11,7 +11,7 @@ module Gitlab
include Gitlab::EncodingHelper
def ref_name(ref)
- encode_utf8(ref).sub(/\Arefs\/(tags|heads|remotes)\//, '')
+ encode!(ref).sub(/\Arefs\/(tags|heads|remotes)\//, '')
end
def branch_name(ref)
diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb
index 228d97a87ab..a1755143abe 100644
--- a/lib/gitlab/git/blob.rb
+++ b/lib/gitlab/git/blob.rb
@@ -50,10 +50,19 @@ module Gitlab
# to the caller to limit the number of blobs and blob_size_limit.
#
# Gitaly migration issue: https://gitlab.com/gitlab-org/gitaly/issues/798
- def batch(repository, blob_references, blob_size_limit: nil)
- blob_size_limit ||= MAX_DATA_DISPLAY_SIZE
- blob_references.map do |sha, path|
- find_by_rugged(repository, sha, path, limit: blob_size_limit)
+ def batch(repository, blob_references, blob_size_limit: MAX_DATA_DISPLAY_SIZE)
+ Gitlab::GitalyClient.migrate(:list_blobs_by_sha_path) do |is_enabled|
+ if is_enabled
+ Gitlab::GitalyClient.allow_n_plus_1_calls do
+ blob_references.map do |sha, path|
+ find_by_gitaly(repository, sha, path, limit: blob_size_limit)
+ end
+ end
+ else
+ blob_references.map do |sha, path|
+ find_by_rugged(repository, sha, path, limit: blob_size_limit)
+ end
+ end
end
end
@@ -122,13 +131,23 @@ module Gitlab
)
end
- def find_by_gitaly(repository, sha, path)
+ def find_by_gitaly(repository, sha, path, limit: MAX_DATA_DISPLAY_SIZE)
path = path.sub(/\A\/*/, '')
path = '/' if path.empty?
name = File.basename(path)
- entry = Gitlab::GitalyClient::CommitService.new(repository).tree_entry(sha, path, MAX_DATA_DISPLAY_SIZE)
+
+ # Gitaly will think that setting the limit to 0 means unlimited, while
+ # the client might only need the metadata and thus set the limit to 0.
+ # In this method we'll then set the limit to 1, but clear the byte of data
+ # that we got back so for the outside world it looks like the limit was
+ # actually 0.
+ req_limit = limit == 0 ? 1 : limit
+
+ entry = Gitlab::GitalyClient::CommitService.new(repository).tree_entry(sha, path, req_limit)
return unless entry
+ entry.data = "" if limit == 0
+
case entry.type
when :COMMIT
new(
diff --git a/lib/gitlab/git/operation_service.rb b/lib/gitlab/git/operation_service.rb
index ef5bdbaf819..3fb0e2eed93 100644
--- a/lib/gitlab/git/operation_service.rb
+++ b/lib/gitlab/git/operation_service.rb
@@ -97,6 +97,11 @@ module Gitlab
end
end
+ def update_branch(branch_name, newrev, oldrev)
+ ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
+ update_ref_in_hooks(ref, newrev, oldrev)
+ end
+
private
# Returns [newrev, should_run_after_create, should_run_after_create_branch]
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index aec85f971ca..e8b1788e140 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -498,11 +498,13 @@ module Gitlab
end
def count_commits(options)
+ count_commits_options = process_count_commits_options(options)
+
gitaly_migrate(:count_commits) do |is_enabled|
if is_enabled
- count_commits_by_gitaly(options)
+ count_commits_by_gitaly(count_commits_options)
else
- count_commits_by_shelling_out(options)
+ count_commits_by_shelling_out(count_commits_options)
end
end
end
@@ -540,8 +542,8 @@ module Gitlab
end
# Counts the amount of commits between `from` and `to`.
- def count_commits_between(from, to)
- count_commits(ref: "#{from}..#{to}")
+ def count_commits_between(from, to, options = {})
+ count_commits(from: from, to: to, **options)
end
# Returns the SHA of the most recent common ancestor of +from+ and +to+
@@ -1219,9 +1221,16 @@ module Gitlab
rebase_path = worktree_path(REBASE_WORKTREE_PREFIX, rebase_id)
env = git_env_for_user(user)
+ if remote_repository.is_a?(RemoteRepository)
+ env.merge!(remote_repository.fetch_env)
+ remote_repo_path = GITALY_INTERNAL_URL
+ else
+ remote_repo_path = remote_repository.path
+ end
+
with_worktree(rebase_path, branch, env: env) do
run_git!(
- %W(pull --rebase #{remote_repository.path} #{remote_branch}),
+ %W(pull --rebase #{remote_repo_path} #{remote_branch}),
chdir: rebase_path, env: env
)
@@ -1461,6 +1470,26 @@ module Gitlab
end
end
+ def process_count_commits_options(options)
+ if options[:from] || options[:to]
+ ref =
+ if options[:left_right] # Compare with merge-base for left-right
+ "#{options[:from]}...#{options[:to]}"
+ else
+ "#{options[:from]}..#{options[:to]}"
+ end
+
+ options.merge(ref: ref)
+
+ elsif options[:ref] && options[:left_right]
+ from, to = options[:ref].match(/\A([^\.]*)\.{2,3}([^\.]*)\z/)[1..2]
+
+ options.merge(from: from, to: to)
+ else
+ options
+ end
+ end
+
def log_using_shell?(options)
options[:path].present? ||
options[:disable_walk] ||
@@ -1683,20 +1712,59 @@ module Gitlab
end
def count_commits_by_gitaly(options)
- gitaly_commit_client.commit_count(options[:ref], options)
+ if options[:left_right]
+ from = options[:from]
+ to = options[:to]
+
+ right_count = gitaly_commit_client
+ .commit_count("#{from}..#{to}", options)
+ left_count = gitaly_commit_client
+ .commit_count("#{to}..#{from}", options)
+
+ [left_count, right_count]
+ else
+ gitaly_commit_client.commit_count(options[:ref], options)
+ end
end
def count_commits_by_shelling_out(options)
+ cmd = count_commits_shelling_command(options)
+
+ raw_output = IO.popen(cmd) { |io| io.read }
+
+ process_count_commits_raw_output(raw_output, options)
+ end
+
+ def count_commits_shelling_command(options)
cmd = %W[#{Gitlab.config.git.bin_path} --git-dir=#{path} rev-list]
cmd << "--after=#{options[:after].iso8601}" if options[:after]
cmd << "--before=#{options[:before].iso8601}" if options[:before]
cmd << "--max-count=#{options[:max_count]}" if options[:max_count]
+ cmd << "--left-right" if options[:left_right]
cmd += %W[--count #{options[:ref]}]
cmd += %W[-- #{options[:path]}] if options[:path].present?
+ cmd
+ end
- raw_output = IO.popen(cmd) { |io| io.read }
+ def process_count_commits_raw_output(raw_output, options)
+ if options[:left_right]
+ result = raw_output.scan(/\d+/).map(&:to_i)
+
+ if result.sum != options[:max_count]
+ result
+ else # Reaching max count, right is not accurate
+ right_option =
+ process_count_commits_options(options
+ .except(:left_right, :from, :to)
+ .merge(ref: options[:to]))
+
+ right = count_commits_by_shelling_out(right_option)
- raw_output.to_i
+ [result.first, right] # left should be accurate in the first call
+ end
+ else
+ raw_output.to_i
+ end
end
def gitaly_ls_files(ref)
diff --git a/lib/gitlab/import_export/command_line_util.rb b/lib/gitlab/import_export/command_line_util.rb
index 0135b3c6f22..dd5d35feab9 100644
--- a/lib/gitlab/import_export/command_line_util.rb
+++ b/lib/gitlab/import_export/command_line_util.rb
@@ -15,6 +15,11 @@ module Gitlab
execute(%W(#{git_bin_path} --git-dir=#{repo_path} bundle create #{bundle_path} --all))
end
+ def git_clone_bundle(repo_path:, bundle_path:)
+ execute(%W(#{git_bin_path} clone --bare -- #{bundle_path} #{repo_path}))
+ Gitlab::Git::Repository.create_hooks(repo_path, File.expand_path(Gitlab.config.gitlab_shell.hooks_path))
+ end
+
def mkdir_p(path)
FileUtils.mkdir_p(path, mode: DEFAULT_MODE)
FileUtils.chmod(DEFAULT_MODE, path)
diff --git a/lib/gitlab/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb
index 32ca2809b2f..d0e5cfcfd3e 100644
--- a/lib/gitlab/import_export/repo_restorer.rb
+++ b/lib/gitlab/import_export/repo_restorer.rb
@@ -13,7 +13,7 @@ module Gitlab
def restore
return true unless File.exist?(@path_to_bundle)
- gitlab_shell.import_repository(@project.repository_storage_path, @project.disk_path, @path_to_bundle)
+ git_clone_bundle(repo_path: @project.repository.path_to_repo, bundle_path: @path_to_bundle)
rescue => e
@shared.error(e)
false
diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb
index 0afaa2306b5..76863e77dc3 100644
--- a/lib/gitlab/ldap/adapter.rb
+++ b/lib/gitlab/ldap/adapter.rb
@@ -74,7 +74,7 @@ module Gitlab
def user_options(fields, value, limit)
options = {
- attributes: Gitlab::LDAP::Person.ldap_attributes(config).compact.uniq,
+ attributes: Gitlab::LDAP::Person.ldap_attributes(config),
base: config.base
}
diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb
index c8f19cd52d5..0d9a554fc18 100644
--- a/lib/gitlab/ldap/config.rb
+++ b/lib/gitlab/ldap/config.rb
@@ -148,7 +148,7 @@ module Gitlab
def default_attributes
{
- 'username' => %w(uid userid sAMAccountName),
+ 'username' => %w(uid sAMAccountName userid),
'email' => %w(mail email userPrincipalName),
'name' => 'cn',
'first_name' => 'givenName',
diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb
index 38d7a9ba2f5..e81cec6ba1a 100644
--- a/lib/gitlab/ldap/person.rb
+++ b/lib/gitlab/ldap/person.rb
@@ -6,6 +6,8 @@ module Gitlab
# Source: http://ctogonewild.com/2009/09/03/bitmask-searches-in-ldap/
AD_USER_DISABLED = Net::LDAP::Filter.ex("userAccountControl:1.2.840.113556.1.4.803", "2")
+ InvalidEntryError = Class.new(StandardError)
+
attr_accessor :entry, :provider
def self.find_by_uid(uid, adapter)
@@ -29,11 +31,12 @@ module Gitlab
def self.ldap_attributes(config)
[
- 'dn', # Used in `dn`
- config.uid, # Used in `uid`
- *config.attributes['name'], # Used in `name`
- *config.attributes['email'] # Used in `email`
- ]
+ 'dn',
+ config.uid,
+ *config.attributes['name'],
+ *config.attributes['email'],
+ *config.attributes['username']
+ ].compact.uniq
end
def self.normalize_dn(dn)
@@ -60,6 +63,8 @@ module Gitlab
Rails.logger.debug { "Instantiating #{self.class.name} with LDIF:\n#{entry.to_ldif}" }
@entry = entry
@provider = provider
+
+ validate_entry
end
def name
@@ -71,7 +76,13 @@ module Gitlab
end
def username
- uid
+ username = attribute_value(:username)
+
+ # Depending on the attribute, multiple values may
+ # be returned. We need only one for username.
+ # Ex. `uid` returns only one value but `mail` may
+ # return an array of multiple email addresses.
+ [username].flatten.first
end
def email
@@ -104,6 +115,19 @@ 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
diff --git a/lib/gitlab/setup_helper.rb b/lib/gitlab/setup_helper.rb
new file mode 100644
index 00000000000..d01213bb6e0
--- /dev/null
+++ b/lib/gitlab/setup_helper.rb
@@ -0,0 +1,61 @@
+module Gitlab
+ module SetupHelper
+ class << self
+ # We cannot create config.toml files for all possible Gitaly configuations.
+ # For instance, if Gitaly is running on another machine then it makes no
+ # sense to write a config.toml file on the current machine. This method will
+ # only generate a configuration for the most common and simplest case: when
+ # we have exactly one Gitaly process and we are sure it is running locally
+ # because it uses a Unix socket.
+ # For development and testing purposes, an extra storage is added to gitaly,
+ # which is not known to Rails, but must be explicitly stubbed.
+ def gitaly_configuration_toml(gitaly_dir, gitaly_ruby: true)
+ storages = []
+ address = nil
+
+ Gitlab.config.repositories.storages.each do |key, val|
+ if address
+ if address != val['gitaly_address']
+ raise ArgumentError, "Your gitlab.yml contains more than one gitaly_address."
+ end
+ elsif URI(val['gitaly_address']).scheme != 'unix'
+ raise ArgumentError, "Automatic config.toml generation only supports 'unix:' addresses."
+ else
+ address = val['gitaly_address']
+ end
+
+ storages << { name: key, path: val['path'] }
+ end
+
+ if Rails.env.test?
+ storages << { name: 'test_second_storage', path: Rails.root.join('tmp', 'tests', 'second_storage').to_s }
+ end
+
+ config = { socket_path: address.sub(%r{\Aunix:}, ''), storage: storages }
+ config[:auth] = { token: 'secret' } if Rails.env.test?
+ config[:'gitaly-ruby'] = { dir: File.join(gitaly_dir, 'ruby') } if gitaly_ruby
+ config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path }
+ config[:bin_dir] = Gitlab.config.gitaly.client_path
+
+ TOML.dump(config)
+ end
+
+ # rubocop:disable Rails/Output
+ def create_gitaly_configuration(dir, force: false)
+ config_path = File.join(dir, 'config.toml')
+ FileUtils.rm_f(config_path) if force
+
+ File.open(config_path, File::WRONLY | File::CREAT | File::EXCL) do |f|
+ f.puts gitaly_configuration_toml(dir)
+ end
+ rescue Errno::EEXIST
+ puts "Skipping config.toml generation:"
+ puts "A configuration file already exists."
+ rescue ArgumentError => e
+ puts "Skipping config.toml generation:"
+ puts e.message
+ end
+ # rubocop:enable Rails/Output
+ end
+ end
+end
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index 40650fc5ee7..564047bbd34 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -71,7 +71,6 @@ module Gitlab
# Ex.
# add_repository("/path/to/storage", "gitlab/gitlab-ci")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def add_repository(storage, name)
relative_path = name.dup
relative_path << '.git' unless relative_path.end_with?('.git')
@@ -100,8 +99,12 @@ module Gitlab
# Ex.
# import_repository("/path/to/storage", "gitlab/gitlab-ci", "https://gitlab.com/gitlab-org/gitlab-test.git")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
+ # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/874
def import_repository(storage, name, url)
+ if url.start_with?('.', '/')
+ raise Error.new("don't use disk paths with import_repository: #{url.inspect}")
+ end
+
# The timeout ensures the subprocess won't hang forever
cmd = gitlab_projects(storage, "#{name}.git")
success = cmd.import_project(url, git_timeout)
@@ -122,7 +125,6 @@ module Gitlab
# Ex.
# fetch_remote(my_repo, "upstream")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
def fetch_remote(repository, remote, ssh_auth: nil, forced: false, no_tags: false)
gitaly_migrate(:fetch_remote) do |is_enabled|
if is_enabled
@@ -142,7 +144,7 @@ module Gitlab
# Ex.
# mv_repository("/path/to/storage", "gitlab/gitlab-ci", "randx/gitlab-ci-new")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
+ # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/873
def mv_repository(storage, path, new_path)
gitlab_projects(storage, "#{path}.git").mv_project("#{new_path}.git")
end
@@ -156,7 +158,7 @@ module Gitlab
# Ex.
# fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "new-namespace/gitlab-ci")
#
- # Gitaly note: JV: not easy to migrate because this involves two Gitaly servers, not one.
+ # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/817
def fork_repository(forked_from_storage, forked_from_disk_path, forked_to_storage, forked_to_disk_path)
gitlab_projects(forked_from_storage, "#{forked_from_disk_path}.git")
.fork_repository(forked_to_storage, "#{forked_to_disk_path}.git")
@@ -170,7 +172,7 @@ module Gitlab
# Ex.
# remove_repository("/path/to/storage", "gitlab/gitlab-ci")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/387
+ # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/873
def remove_repository(storage, name)
gitlab_projects(storage, "#{name}.git").rm_project
end
@@ -221,7 +223,6 @@ module Gitlab
# Ex.
# add_namespace("/path/to/storage", "gitlab")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def add_namespace(storage, name)
Gitlab::GitalyClient.migrate(:add_namespace) do |enabled|
if enabled
@@ -243,7 +244,6 @@ module Gitlab
# Ex.
# rm_namespace("/path/to/storage", "gitlab")
#
- # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/385
def rm_namespace(storage, name)
Gitlab::GitalyClient.migrate(:remove_namespace) do |enabled|
if enabled
@@ -261,7 +261,6 @@ module Gitlab
# Ex.
# mv_namespace("/path/to/storage", "gitlab", "gitlabhq")
#
- # 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|
if enabled
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index dfade1f3885..903e84359cd 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -387,14 +387,8 @@ namespace :gitlab do
namespace :repo do
desc "GitLab | Check the integrity of the repositories managed by GitLab"
task check: :environment do
- Gitlab.config.repositories.storages.each do |name, repository_storage|
- namespace_dirs = Dir.glob(File.join(repository_storage['path'], '*'))
-
- namespace_dirs.each do |namespace_dir|
- repo_dirs = Dir.glob(File.join(namespace_dir, '*'))
- repo_dirs.each { |repo_dir| check_repo_integrity(repo_dir) }
- end
- end
+ puts "This task is deprecated. Please use gitlab:git:fsck instead".color(:red)
+ Rake::Task["gitlab:git:fsck"].execute
end
end
@@ -461,35 +455,4 @@ namespace :gitlab do
puts "FAIL. Please update gitlab-shell to #{required_version} from #{current_version}".color(:red)
end
end
-
- def check_repo_integrity(repo_dir)
- puts "\nChecking repo at #{repo_dir.color(:yellow)}"
-
- git_fsck(repo_dir)
- check_config_lock(repo_dir)
- check_ref_locks(repo_dir)
- end
-
- def git_fsck(repo_dir)
- puts "Running `git fsck`".color(:yellow)
- system(*%W(#{Gitlab.config.git.bin_path} fsck), chdir: repo_dir)
- end
-
- def check_config_lock(repo_dir)
- config_exists = File.exist?(File.join(repo_dir, 'config.lock'))
- config_output = config_exists ? 'yes'.color(:red) : 'no'.color(:green)
- puts "'config.lock' file exists?".color(:yellow) + " ... #{config_output}"
- end
-
- def check_ref_locks(repo_dir)
- lock_files = Dir.glob(File.join(repo_dir, 'refs/heads/*.lock'))
- if lock_files.present?
- puts "Ref lock files exist:".color(:red)
- lock_files.each do |lock_file|
- puts " #{lock_file}"
- end
- else
- puts "No ref lock files exist".color(:green)
- end
- end
end
diff --git a/lib/tasks/gitlab/git.rake b/lib/tasks/gitlab/git.rake
index cf82134d97e..3f5dd2ae3b3 100644
--- a/lib/tasks/gitlab/git.rake
+++ b/lib/tasks/gitlab/git.rake
@@ -30,6 +30,20 @@ namespace :gitlab do
end
end
+ desc 'GitLab | Git | Check all repos integrity'
+ task fsck: :environment do
+ failures = perform_git_cmd(%W(#{Gitlab.config.git.bin_path} fsck --name-objects --no-progress), "Checking integrity") do |repo|
+ check_config_lock(repo)
+ check_ref_locks(repo)
+ end
+
+ if failures.empty?
+ puts "Done".color(:green)
+ else
+ output_failures(failures)
+ end
+ end
+
def perform_git_cmd(cmd, message)
puts "Starting #{message} on all repositories"
@@ -40,6 +54,8 @@ namespace :gitlab do
else
failures << repo
end
+
+ yield(repo) if block_given?
end
failures
@@ -49,5 +65,24 @@ namespace :gitlab do
puts "The following repositories reported errors:".color(:red)
failures.each { |f| puts "- #{f}" }
end
+
+ def check_config_lock(repo_dir)
+ config_exists = File.exist?(File.join(repo_dir, 'config.lock'))
+ config_output = config_exists ? 'yes'.color(:red) : 'no'.color(:green)
+
+ puts "'config.lock' file exists?".color(:yellow) + " ... #{config_output}"
+ end
+
+ def check_ref_locks(repo_dir)
+ lock_files = Dir.glob(File.join(repo_dir, 'refs/heads/*.lock'))
+
+ if lock_files.present?
+ puts "Ref lock files exist:".color(:red)
+
+ lock_files.each { |lock_file| puts " #{lock_file}" }
+ else
+ puts "No ref lock files exist".color(:green)
+ end
+ end
end
end
diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake
index 4d880c05f99..4507b841964 100644
--- a/lib/tasks/gitlab/gitaly.rake
+++ b/lib/tasks/gitlab/gitaly.rake
@@ -21,8 +21,8 @@ namespace :gitlab do
command << 'BUNDLE_FLAGS=--no-deployment' if Rails.env.test?
+ Gitlab::SetupHelper.create_gitaly_configuration(args.dir)
Dir.chdir(args.dir) do
- create_gitaly_configuration
# In CI we run scripts/gitaly-test-build instead of this command
unless ENV['CI'].present?
Bundler.with_original_env { run_command!(command) }
@@ -39,60 +39,7 @@ namespace :gitlab do
# Exclude gitaly-ruby configuration because that depends on the gitaly
# installation directory.
- puts gitaly_configuration_toml(gitaly_ruby: false)
- end
-
- private
-
- # We cannot create config.toml files for all possible Gitaly configuations.
- # For instance, if Gitaly is running on another machine then it makes no
- # sense to write a config.toml file on the current machine. This method will
- # only generate a configuration for the most common and simplest case: when
- # we have exactly one Gitaly process and we are sure it is running locally
- # because it uses a Unix socket.
- # For development and testing purposes, an extra storage is added to gitaly,
- # which is not known to Rails, but must be explicitly stubbed.
- def gitaly_configuration_toml(gitaly_ruby: true)
- storages = []
- address = nil
-
- Gitlab.config.repositories.storages.each do |key, val|
- if address
- if address != val['gitaly_address']
- raise ArgumentError, "Your gitlab.yml contains more than one gitaly_address."
- end
- elsif URI(val['gitaly_address']).scheme != 'unix'
- raise ArgumentError, "Automatic config.toml generation only supports 'unix:' addresses."
- else
- address = val['gitaly_address']
- end
-
- storages << { name: key, path: val['path'] }
- end
-
- if Rails.env.test?
- storages << { name: 'test_second_storage', path: Rails.root.join('tmp', 'tests', 'second_storage').to_s }
- end
-
- config = { socket_path: address.sub(%r{\Aunix:}, ''), storage: storages }
- config[:auth] = { token: 'secret' } if Rails.env.test?
- config[:'gitaly-ruby'] = { dir: File.join(Dir.pwd, 'ruby') } if gitaly_ruby
- config[:'gitlab-shell'] = { dir: Gitlab.config.gitlab_shell.path }
- config[:bin_dir] = Gitlab.config.gitaly.client_path
-
- TOML.dump(config)
- end
-
- def create_gitaly_configuration
- File.open("config.toml", File::WRONLY | File::CREAT | File::EXCL) do |f|
- f.puts gitaly_configuration_toml
- end
- rescue Errno::EEXIST
- puts "Skipping config.toml generation:"
- puts "A configuration file already exists."
- rescue ArgumentError => e
- puts "Skipping config.toml generation:"
- puts e.message
+ puts Gitlab::SetupHelper.gitaly_configuration_toml('', gitaly_ruby: false)
end
end
end
diff --git a/lib/tasks/gitlab/task_helpers.rb b/lib/tasks/gitlab/task_helpers.rb
index 6723662703c..c1182af1014 100644
--- a/lib/tasks/gitlab/task_helpers.rb
+++ b/lib/tasks/gitlab/task_helpers.rb
@@ -130,7 +130,7 @@ module Gitlab
def all_repos
Gitlab.config.repositories.storages.each_value do |repository_storage|
- IO.popen(%W(find #{repository_storage['path']} -mindepth 2 -maxdepth 2 -type d -name *.git)) do |find|
+ IO.popen(%W(find #{repository_storage['path']} -mindepth 2 -type d -name *.git)) do |find|
find.each_line do |path|
yield path.chomp
end