summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/api/entities.rb1
-rw-r--r--lib/api/features.rb7
-rw-r--r--lib/api/helpers.rb13
-rw-r--r--lib/api/projects.rb2
-rw-r--r--lib/api/runner.rb3
-rw-r--r--lib/banzai/filter/abstract_reference_filter.rb4
-rw-r--r--lib/banzai/filter/commit_range_reference_filter.rb2
-rw-r--r--lib/banzai/filter/commit_trailers_filter.rb152
-rw-r--r--lib/banzai/filter/label_reference_filter.rb4
-rw-r--r--lib/banzai/filter/merge_request_reference_filter.rb39
-rw-r--r--lib/banzai/filter/milestone_reference_filter.rb2
-rw-r--r--lib/banzai/pipeline/commit_description_pipeline.rb11
-rw-r--r--lib/gitlab/auth/ldap/access.rb2
-rw-r--r--lib/gitlab/auth/ldap/adapter.rb43
-rw-r--r--lib/gitlab/auth/ldap/ldap_connection_error.rb7
-rw-r--r--lib/gitlab/auth/o_auth/user.rb3
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb2
-rw-r--r--lib/gitlab/git/checksum.rb82
-rw-r--r--lib/gitlab/git/gitlab_projects.rb57
-rw-r--r--lib/gitlab/git/repository.rb5
-rw-r--r--lib/gitlab/github_import/importer/repository_importer.rb3
-rw-r--r--lib/gitlab/legacy_github_import/importer.rb2
-rw-r--r--lib/gitlab/shell.rb25
-rw-r--r--lib/gitlab/sidekiq_logging/json_formatter.rb21
-rw-r--r--lib/gitlab/sidekiq_logging/structured_logger.rb96
-rw-r--r--lib/tasks/gitlab/two_factor.rake2
-rw-r--r--lib/tasks/test.rake5
27 files changed, 520 insertions, 75 deletions
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index b7a390696c7..e5ecd37e473 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -206,6 +206,7 @@ module API
expose :request_access_enabled
expose :only_allow_merge_if_all_discussions_are_resolved
expose :printing_merge_request_link_enabled
+ expose :merge_method
expose :statistics, using: 'API::Entities::ProjectStatistics', if: :statistics
diff --git a/lib/api/features.rb b/lib/api/features.rb
index 9385c6ca174..11d848584d9 100644
--- a/lib/api/features.rb
+++ b/lib/api/features.rb
@@ -65,6 +65,13 @@ module API
present feature, with: Entities::Feature, current_user: current_user
end
+
+ desc 'Remove the gate value for the given feature'
+ delete ':name' do
+ Feature.get(params[:name]).remove
+
+ status 204
+ end
end
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index e59e8a45908..61c138a7dec 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -83,12 +83,13 @@ module API
end
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
+ search_params = { include_ancestor_groups: true }
+
+ if label_parent.is_a?(Project)
+ search_params[:project_id] = label_parent.id
+ else
+ search_params.merge!(group_id: label_parent.id, only_group_labels: true)
+ end
LabelsFinder.new(current_user, search_params).execute
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 467bc78dad8..3d5b3c5a535 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -28,6 +28,7 @@ module API
optional :tag_list, type: Array[String], desc: 'The list of tags for a project'
optional :avatar, type: File, desc: 'Avatar image for project'
optional :printing_merge_request_link_enabled, type: Boolean, desc: 'Show link to create/view merge request when pushing from the command line'
+ optional :merge_method, type: String, values: %w(ff rebase_merge merge), desc: 'The merge method used when merging merge requests'
end
params :optional_params do
@@ -274,6 +275,7 @@ module API
:issues_enabled,
:lfs_enabled,
:merge_requests_enabled,
+ :merge_method,
:name,
:only_allow_merge_if_all_discussions_are_resolved,
:only_allow_merge_if_pipeline_succeeds,
diff --git a/lib/api/runner.rb b/lib/api/runner.rb
index 57c0a729535..834253d8e94 100644
--- a/lib/api/runner.rb
+++ b/lib/api/runner.rb
@@ -208,6 +208,7 @@ module API
optional 'file.sha256', type: String, desc: %q(sha256 checksum of the file)
optional 'metadata.path', type: String, desc: %q(path to locally stored body (generated by Workhorse))
optional 'metadata.name', type: String, desc: %q(filename (generated by Workhorse))
+ optional 'metadata.sha256', type: String, desc: %q(sha256 checksum of the file)
end
post '/:id/artifacts' do
not_allowed! unless Gitlab.config.artifacts.enabled
@@ -227,7 +228,7 @@ module API
Gitlab::CurrentSettings.current_application_settings.default_artifacts_expire_in
job.build_job_artifacts_archive(project: job.project, file_type: :archive, file: artifacts, file_sha256: params['file.sha256'], expire_in: expire_in)
- job.build_job_artifacts_metadata(project: job.project, file_type: :metadata, file: metadata, expire_in: expire_in) if metadata
+ job.build_job_artifacts_metadata(project: job.project, file_type: :metadata, file: metadata, file_sha256: params['metadata.sha256'], expire_in: expire_in) if metadata
job.artifacts_expire_in = expire_in
if job.save
diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb
index c9e3f8ce42b..c3a03f13306 100644
--- a/lib/banzai/filter/abstract_reference_filter.rb
+++ b/lib/banzai/filter/abstract_reference_filter.rb
@@ -171,7 +171,7 @@ module Banzai
end
if object
- title = object_link_title(object)
+ title = object_link_title(object, matches)
klass = reference_class(object_sym)
data = data_attributes_for(link_content || match, parent, object,
@@ -216,7 +216,7 @@ module Banzai
extras
end
- def object_link_title(object)
+ def object_link_title(object, matches)
object.title
end
diff --git a/lib/banzai/filter/commit_range_reference_filter.rb b/lib/banzai/filter/commit_range_reference_filter.rb
index 21bcb1c5ca8..99fa2d9d8fb 100644
--- a/lib/banzai/filter/commit_range_reference_filter.rb
+++ b/lib/banzai/filter/commit_range_reference_filter.rb
@@ -34,7 +34,7 @@ module Banzai
range.to_param.merge(only_path: context[:only_path]))
end
- def object_link_title(range)
+ def object_link_title(range, matches)
nil
end
end
diff --git a/lib/banzai/filter/commit_trailers_filter.rb b/lib/banzai/filter/commit_trailers_filter.rb
new file mode 100644
index 00000000000..ef16df1f3ae
--- /dev/null
+++ b/lib/banzai/filter/commit_trailers_filter.rb
@@ -0,0 +1,152 @@
+module Banzai
+ module Filter
+ # HTML filter that replaces users' names and emails in commit trailers
+ # with links to their GitLab accounts or mailto links to their mentioned
+ # emails.
+ #
+ # Commit trailers are special labels in the form of `*-by:` and fall on a
+ # single line, ex:
+ #
+ # Reported-By: John S. Doe <john.doe@foo.bar>
+ #
+ # More info about this can be found here:
+ # * https://git.wiki.kernel.org/index.php/CommitMessageConventions
+ class CommitTrailersFilter < HTML::Pipeline::Filter
+ include ActionView::Helpers::TagHelper
+ include ApplicationHelper
+ include AvatarsHelper
+
+ TRAILER_REGEXP = /(?<label>[[:alpha:]-]+-by:)/i.freeze
+ AUTHOR_REGEXP = /(?<author_name>.+)/.freeze
+ # Devise.email_regexp wouldn't work here since its designed to match
+ # against strings that only contains email addresses; the \A and \z
+ # around the expression will only match if the string being matched
+ # contains just the email nothing else.
+ MAIL_REGEXP = /&lt;(?<author_email>[^@\s]+@[^@\s]+)&gt;/.freeze
+ FILTER_REGEXP = /(?<trailer>^\s*#{TRAILER_REGEXP}\s*#{AUTHOR_REGEXP}\s+#{MAIL_REGEXP}$)/mi.freeze
+
+ def call
+ doc.xpath('descendant-or-self::text()').each do |node|
+ content = node.to_html
+
+ next unless content.match(FILTER_REGEXP)
+
+ html = trailer_filter(content)
+
+ next if html == content
+
+ node.replace(html)
+ end
+
+ doc
+ end
+
+ private
+
+ # Replace trailer lines with links to GitLab users or mailto links to
+ # non GitLab users.
+ #
+ # text - String text to replace trailers in.
+ #
+ # Returns a String with all trailer lines replaced with links to GitLab
+ # users and mailto links to non GitLab users. All links have `data-trailer`
+ # and `data-user` attributes attached.
+ def trailer_filter(text)
+ text.gsub(FILTER_REGEXP) do |author_match|
+ label = $~[:label]
+ "#{label} #{parse_user($~[:author_name], $~[:author_email], label)}"
+ end
+ end
+
+ # Find a GitLab user using the supplied email and generate
+ # a valid link to them, otherwise, generate a mailto link.
+ #
+ # name - String name used in the commit message for the user
+ # email - String email used in the commit message for the user
+ # trailer - String trailer used in the commit message
+ #
+ # Returns a String with a link to the user.
+ def parse_user(name, email, trailer)
+ link_to_user User.find_by_any_email(email),
+ name: name,
+ email: email,
+ trailer: trailer
+ end
+
+ def urls
+ Gitlab::Routing.url_helpers
+ end
+
+ def link_to_user(user, name:, email:, trailer:)
+ wrapper = link_wrapper(data: {
+ trailer: trailer,
+ user: user.try(:id)
+ })
+
+ avatar = user_avatar_without_link(
+ user: user,
+ user_email: email,
+ css_class: 'avatar-inline',
+ has_tooltip: false
+ )
+
+ link_href = user.nil? ? "mailto:#{email}" : urls.user_url(user)
+
+ avatar_link = link_tag(
+ link_href,
+ content: avatar,
+ title: email
+ )
+
+ name_link = link_tag(
+ link_href,
+ content: name,
+ title: email
+ )
+
+ email_link = link_tag(
+ "mailto:#{email}",
+ content: email,
+ title: email
+ )
+
+ wrapper << "#{avatar_link}#{name_link} <#{email_link}>"
+ end
+
+ def link_wrapper(data: {})
+ data_attributes = data_attributes_from_hash(data)
+
+ doc.document.create_element(
+ 'span',
+ data_attributes
+ )
+ end
+
+ def link_tag(url, title: "", content: "", data: {})
+ data_attributes = data_attributes_from_hash(data)
+
+ attributes = data_attributes.merge(
+ href: url,
+ title: title
+ )
+
+ link = doc.document.create_element('a', attributes)
+
+ if content.html_safe?
+ link << content
+ else
+ link.content = content # make sure we escape content using nokogiri's #content=
+ end
+
+ link
+ end
+
+ def data_attributes_from_hash(data = {})
+ data.reject! {|_, value| value.nil?}
+ data.map do |key, value|
+ [%(data-#{key.to_s.dasherize}), value]
+ end.to_h
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb
index d5360ad8f68..faa5b344e6f 100644
--- a/lib/banzai/filter/label_reference_filter.rb
+++ b/lib/banzai/filter/label_reference_filter.rb
@@ -41,7 +41,7 @@ module Banzai
end
def find_labels(project)
- LabelsFinder.new(nil, project_id: project.id).execute(skip_authorization: true)
+ LabelsFinder.new(nil, project_id: project.id, include_ancestor_groups: true).execute(skip_authorization: true)
end
# Parameters to pass to `Label.find_by` based on the given arguments
@@ -77,7 +77,7 @@ module Banzai
CGI.unescapeHTML(text.to_s)
end
- def object_link_title(object)
+ def object_link_title(object, matches)
# use title of wrapped element instead
nil
end
diff --git a/lib/banzai/filter/merge_request_reference_filter.rb b/lib/banzai/filter/merge_request_reference_filter.rb
index b3cfa97d0e0..5cbdb01c130 100644
--- a/lib/banzai/filter/merge_request_reference_filter.rb
+++ b/lib/banzai/filter/merge_request_reference_filter.rb
@@ -17,10 +17,19 @@ module Banzai
only_path: context[:only_path])
end
+ def object_link_title(object, matches)
+ object_link_commit_title(object, matches) || super
+ end
+
def object_link_text_extras(object, matches)
extras = super
+ if commit_ref = object_link_commit_ref(object, matches)
+ return extras.unshift(commit_ref)
+ end
+
path = matches[:path] if matches.names.include?("path")
+
case path
when '/diffs'
extras.unshift "diffs"
@@ -38,6 +47,36 @@ module Banzai
.where(iid: ids.to_a)
.includes(target_project: :namespace)
end
+
+ private
+
+ def object_link_commit_title(object, matches)
+ object_link_commit(object, matches)&.title
+ end
+
+ def object_link_commit_ref(object, matches)
+ object_link_commit(object, matches)&.short_id
+ end
+
+ def object_link_commit(object, matches)
+ return unless matches.names.include?('query') && query = matches[:query]
+
+ # Removes leading "?". CGI.parse expects "arg1&arg2&arg3"
+ params = CGI.parse(query.sub(/^\?/, ''))
+
+ return unless commit_sha = params['commit_id']&.first
+
+ if commit = find_commit_by_sha(object, commit_sha)
+ Commit.from_hash(commit.to_hash, object.project)
+ end
+ end
+
+ def find_commit_by_sha(object, commit_sha)
+ @all_commits ||= {}
+ @all_commits[object.id] ||= object.all_commits
+
+ @all_commits[object.id].find { |commit| commit.sha == commit_sha }
+ end
end
end
end
diff --git a/lib/banzai/filter/milestone_reference_filter.rb b/lib/banzai/filter/milestone_reference_filter.rb
index 8ec696ce5fc..1a1d7dbeb3d 100644
--- a/lib/banzai/filter/milestone_reference_filter.rb
+++ b/lib/banzai/filter/milestone_reference_filter.rb
@@ -84,7 +84,7 @@ module Banzai
end
end
- def object_link_title(object)
+ def object_link_title(object, matches)
nil
end
end
diff --git a/lib/banzai/pipeline/commit_description_pipeline.rb b/lib/banzai/pipeline/commit_description_pipeline.rb
new file mode 100644
index 00000000000..607c2731ed3
--- /dev/null
+++ b/lib/banzai/pipeline/commit_description_pipeline.rb
@@ -0,0 +1,11 @@
+module Banzai
+ module Pipeline
+ class CommitDescriptionPipeline < SingleLinePipeline
+ def self.filters
+ @filters ||= super.concat FilterArray[
+ Filter::CommitTrailersFilter,
+ ]
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/ldap/access.rb b/lib/gitlab/auth/ldap/access.rb
index 77c0ddc2d48..34286900e72 100644
--- a/lib/gitlab/auth/ldap/access.rb
+++ b/lib/gitlab/auth/ldap/access.rb
@@ -52,6 +52,8 @@ module Gitlab
block_user(user, 'does not exist anymore')
false
end
+ rescue LDAPConnectionError
+ false
end
def adapter
diff --git a/lib/gitlab/auth/ldap/adapter.rb b/lib/gitlab/auth/ldap/adapter.rb
index caf2d18c668..82ff1e77e5c 100644
--- a/lib/gitlab/auth/ldap/adapter.rb
+++ b/lib/gitlab/auth/ldap/adapter.rb
@@ -2,6 +2,9 @@ module Gitlab
module Auth
module LDAP
class Adapter
+ SEARCH_RETRY_FACTOR = [1, 1, 2, 3].freeze
+ MAX_SEARCH_RETRIES = Rails.env.test? ? 1 : SEARCH_RETRY_FACTOR.size.freeze
+
attr_reader :provider, :ldap
def self.open(provider, &block)
@@ -16,7 +19,7 @@ module Gitlab
def initialize(provider, ldap = nil)
@provider = provider
- @ldap = ldap || Net::LDAP.new(config.adapter_options)
+ @ldap = ldap || renew_connection_adapter
end
def config
@@ -47,8 +50,10 @@ module Gitlab
end
def ldap_search(*args)
+ retries ||= 0
+
# Net::LDAP's `time` argument doesn't work. Use Ruby `Timeout` instead.
- Timeout.timeout(config.timeout) do
+ Timeout.timeout(timeout_time(retries)) do
results = ldap.search(*args)
if results.nil?
@@ -63,16 +68,26 @@ module Gitlab
results
end
end
- rescue Net::LDAP::Error => error
- Rails.logger.warn("LDAP search raised exception #{error.class}: #{error.message}")
- []
- rescue Timeout::Error
- Rails.logger.warn("LDAP search timed out after #{config.timeout} seconds")
- []
+ rescue Net::LDAP::Error, Timeout::Error => error
+ retries += 1
+ error_message = connection_error_message(error)
+
+ Rails.logger.warn(error_message)
+
+ if retries < MAX_SEARCH_RETRIES
+ renew_connection_adapter
+ retry
+ else
+ raise LDAPConnectionError, error_message
+ end
end
private
+ def timeout_time(retry_number)
+ SEARCH_RETRY_FACTOR[retry_number] * config.timeout
+ end
+
def user_options(fields, value, limit)
options = {
attributes: Gitlab::Auth::LDAP::Person.ldap_attributes(config),
@@ -104,6 +119,18 @@ module Gitlab
filter
end
end
+
+ def connection_error_message(exception)
+ if exception.is_a?(Timeout::Error)
+ "LDAP search timed out after #{config.timeout} seconds"
+ else
+ "LDAP search raised exception #{exception.class}: #{exception.message}"
+ end
+ end
+
+ def renew_connection_adapter
+ @ldap = Net::LDAP.new(config.adapter_options)
+ end
end
end
end
diff --git a/lib/gitlab/auth/ldap/ldap_connection_error.rb b/lib/gitlab/auth/ldap/ldap_connection_error.rb
new file mode 100644
index 00000000000..ef0a695742b
--- /dev/null
+++ b/lib/gitlab/auth/ldap/ldap_connection_error.rb
@@ -0,0 +1,7 @@
+module Gitlab
+ module Auth
+ module LDAP
+ LDAPConnectionError = Class.new(StandardError)
+ end
+ end
+end
diff --git a/lib/gitlab/auth/o_auth/user.rb b/lib/gitlab/auth/o_auth/user.rb
index b6a96081278..d0c6b0386ba 100644
--- a/lib/gitlab/auth/o_auth/user.rb
+++ b/lib/gitlab/auth/o_auth/user.rb
@@ -124,6 +124,9 @@ module Gitlab
Gitlab::Auth::LDAP::Person.find_by_uid(auth_hash.uid, adapter) ||
Gitlab::Auth::LDAP::Person.find_by_email(auth_hash.uid, adapter) ||
Gitlab::Auth::LDAP::Person.find_by_dn(auth_hash.uid, adapter)
+
+ rescue Gitlab::Auth::LDAP::LDAPConnectionError
+ nil
end
def ldap_config
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index bffbcb86137..f3999e690fa 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -63,7 +63,7 @@ module Gitlab
disk_path = project.wiki.disk_path
import_url = project.import_url.sub(/\.git\z/, ".git/wiki")
- gitlab_shell.import_repository(project.repository_storage_path, disk_path, import_url)
+ gitlab_shell.import_repository(project.repository_storage, disk_path, import_url)
rescue StandardError => e
errors << { type: :wiki, errors: e.message }
end
diff --git a/lib/gitlab/git/checksum.rb b/lib/gitlab/git/checksum.rb
new file mode 100644
index 00000000000..3ef0f0a8854
--- /dev/null
+++ b/lib/gitlab/git/checksum.rb
@@ -0,0 +1,82 @@
+module Gitlab
+ module Git
+ class Checksum
+ include Gitlab::Git::Popen
+
+ EMPTY_REPOSITORY_CHECKSUM = '0000000000000000000000000000000000000000'.freeze
+
+ Failure = Class.new(StandardError)
+
+ attr_reader :path, :relative_path, :storage, :storage_path
+
+ def initialize(storage, relative_path)
+ @storage = storage
+ @storage_path = Gitlab.config.repositories.storages[storage].legacy_disk_path
+ @relative_path = "#{relative_path}.git"
+ @path = File.join(storage_path, @relative_path)
+ end
+
+ def calculate
+ unless repository_exists?
+ failure!(Gitlab::Git::Repository::NoRepository, 'No repository for such path')
+ end
+
+ calculate_checksum_by_shelling_out
+ end
+
+ private
+
+ def repository_exists?
+ raw_repository.exists?
+ end
+
+ def calculate_checksum_by_shelling_out
+ args = %W(--git-dir=#{path} show-ref --heads --tags)
+ output, status = run_git(args)
+
+ if status&.zero?
+ refs = output.split("\n")
+
+ result = refs.inject(nil) do |checksum, ref|
+ value = Digest::SHA1.hexdigest(ref).hex
+
+ if checksum.nil?
+ value
+ else
+ checksum ^ value
+ end
+ end
+
+ result.to_s(16)
+ else
+ # Empty repositories return with a non-zero status and an empty output.
+ if output&.empty?
+ EMPTY_REPOSITORY_CHECKSUM
+ else
+ failure!(Gitlab::Git::Checksum::Failure, output)
+ end
+ end
+ end
+
+ def failure!(klass, message)
+ Gitlab::GitLogger.error("'git show-ref --heads --tags' in #{path}: #{message}")
+
+ raise klass.new("Could not calculate the checksum for #{path}: #{message}")
+ end
+
+ def circuit_breaker
+ @circuit_breaker ||= Gitlab::Git::Storage::CircuitBreaker.for_storage(storage)
+ end
+
+ def raw_repository
+ Gitlab::Git::Repository.new(storage, relative_path, nil)
+ end
+
+ def run_git(args)
+ circuit_breaker.perform do
+ popen([Gitlab.config.git.bin_path, *args], path)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/git/gitlab_projects.rb b/lib/gitlab/git/gitlab_projects.rb
index dc0bc8518bc..099709620b3 100644
--- a/lib/gitlab/git/gitlab_projects.rb
+++ b/lib/gitlab/git/gitlab_projects.rb
@@ -4,20 +4,14 @@ module Gitlab
include Gitlab::Git::Popen
include Gitlab::Utils::StrongMemoize
- ShardNameNotFoundError = Class.new(StandardError)
-
- # Absolute path to directory where repositories are stored.
- # Example: /home/git/repositories
- attr_reader :shard_path
+ # Name of shard where repositories are stored.
+ # Example: nfs-file06
+ attr_reader :shard_name
# Relative path is a directory name for repository with .git at the end.
# Example: gitlab-org/gitlab-test.git
attr_reader :repository_relative_path
- # Absolute path to the repository.
- # Example: /home/git/repositorities/gitlab-org/gitlab-test.git
- attr_reader :repository_absolute_path
-
# This is the path at which the gitlab-shell hooks directory can be found.
# It's essential for integration between git and GitLab proper. All new
# repositories should have their hooks directory symlinked here.
@@ -25,13 +19,12 @@ module Gitlab
attr_reader :logger
- def initialize(shard_path, repository_relative_path, global_hooks_path:, logger:)
- @shard_path = shard_path
+ def initialize(shard_name, repository_relative_path, global_hooks_path:, logger:)
+ @shard_name = shard_name
@repository_relative_path = repository_relative_path
@logger = logger
@global_hooks_path = global_hooks_path
- @repository_absolute_path = File.join(shard_path, repository_relative_path)
@output = StringIO.new
end
@@ -41,6 +34,22 @@ module Gitlab
io.read
end
+ # Absolute path to the repository.
+ # Example: /home/git/repositorities/gitlab-org/gitlab-test.git
+ # Probably will be removed when we fully migrate to Gitaly, part of
+ # https://gitlab.com/gitlab-org/gitaly/issues/1124.
+ def repository_absolute_path
+ strong_memoize(:repository_absolute_path) do
+ File.join(shard_path, repository_relative_path)
+ end
+ end
+
+ def shard_path
+ strong_memoize(:shard_path) do
+ Gitlab.config.repositories.storages.fetch(shard_name).legacy_disk_path
+ end
+ end
+
# Import project via git clone --bare
# URL must be publicly cloneable
def import_project(source, timeout)
@@ -53,12 +62,12 @@ module Gitlab
end
end
- def fork_repository(new_shard_path, new_repository_relative_path)
+ def fork_repository(new_shard_name, new_repository_relative_path)
Gitlab::GitalyClient.migrate(:fork_repository) do |is_enabled|
if is_enabled
- gitaly_fork_repository(new_shard_path, new_repository_relative_path)
+ gitaly_fork_repository(new_shard_name, new_repository_relative_path)
else
- git_fork_repository(new_shard_path, new_repository_relative_path)
+ git_fork_repository(new_shard_name, new_repository_relative_path)
end
end
end
@@ -205,17 +214,6 @@ module Gitlab
private
- def shard_name
- strong_memoize(:shard_name) do
- shard_name_from_shard_path(shard_path)
- end
- end
-
- def shard_name_from_shard_path(shard_path)
- Gitlab.config.repositories.storages.find { |_, info| info.legacy_disk_path == shard_path }&.first ||
- raise(ShardNameNotFoundError, "no shard found for path '#{shard_path}'")
- end
-
def git_import_repository(source, timeout)
# Skip import if repo already exists
return false if File.exist?(repository_absolute_path)
@@ -252,8 +250,9 @@ module Gitlab
false
end
- def git_fork_repository(new_shard_path, new_repository_relative_path)
+ def git_fork_repository(new_shard_name, new_repository_relative_path)
from_path = repository_absolute_path
+ new_shard_path = Gitlab.config.repositories.storages.fetch(new_shard_name).legacy_disk_path
to_path = File.join(new_shard_path, new_repository_relative_path)
# The repository cannot already exist
@@ -271,8 +270,8 @@ module Gitlab
run(cmd, nil) && Gitlab::Git::Repository.create_hooks(to_path, global_hooks_path)
end
- def gitaly_fork_repository(new_shard_path, new_repository_relative_path)
- target_repository = Gitlab::Git::Repository.new(shard_name_from_shard_path(new_shard_path), new_repository_relative_path, nil)
+ def gitaly_fork_repository(new_shard_name, new_repository_relative_path)
+ target_repository = Gitlab::Git::Repository.new(new_shard_name, new_repository_relative_path, nil)
raw_repository = Gitlab::Git::Repository.new(shard_name, repository_relative_path, nil)
Gitlab::GitalyClient::RepositoryService.new(target_repository).fork_repository(raw_repository)
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index e692c9ce342..8d97bfb0e6a 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -96,7 +96,7 @@ module Gitlab
storage_path = Gitlab.config.repositories.storages[@storage].legacy_disk_path
@gitlab_projects = Gitlab::Git::GitlabProjects.new(
- storage_path,
+ storage,
relative_path,
global_hooks_path: Gitlab.config.gitlab_shell.hooks_path,
logger: Rails.logger
@@ -885,7 +885,8 @@ module Gitlab
end
def delete_refs(*ref_names)
- gitaly_migrate(:delete_refs) do |is_enabled|
+ gitaly_migrate(:delete_refs,
+ status: Gitlab::GitalyClient::MigrationStatus::OPT_OUT) do |is_enabled|
if is_enabled
gitaly_delete_refs(*ref_names)
else
diff --git a/lib/gitlab/github_import/importer/repository_importer.rb b/lib/gitlab/github_import/importer/repository_importer.rb
index b1b283e98b5..01168abde6c 100644
--- a/lib/gitlab/github_import/importer/repository_importer.rb
+++ b/lib/gitlab/github_import/importer/repository_importer.rb
@@ -56,9 +56,8 @@ module Gitlab
def import_wiki_repository
wiki_path = "#{project.disk_path}.wiki"
- storage_path = project.repository_storage_path
- gitlab_shell.import_repository(storage_path, wiki_path, wiki_url)
+ gitlab_shell.import_repository(project.repository_storage, wiki_path, wiki_url)
true
rescue Gitlab::Shell::Error => e
diff --git a/lib/gitlab/legacy_github_import/importer.rb b/lib/gitlab/legacy_github_import/importer.rb
index 0526ef9eb13..7edd0ad2033 100644
--- a/lib/gitlab/legacy_github_import/importer.rb
+++ b/lib/gitlab/legacy_github_import/importer.rb
@@ -259,7 +259,7 @@ module Gitlab
def import_wiki
unless project.wiki.repository_exists?
wiki = WikiFormatter.new(project)
- gitlab_shell.import_repository(project.repository_storage_path, wiki.disk_path, wiki.import_url)
+ gitlab_shell.import_repository(project.repository_storage, wiki.disk_path, wiki.import_url)
end
rescue Gitlab::Shell::Error => e
# GitHub error message when the wiki repo has not been created,
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index c8c15b9684a..67407b651a5 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -93,12 +93,12 @@ module Gitlab
# Import repository
#
- # storage - project's storage path
+ # storage - project's storage name
# name - project disk path
# url - URL to import from
#
# Ex.
- # import_repository("/path/to/storage", "gitlab/gitlab-ci", "https://gitlab.com/gitlab-org/gitlab-test.git")
+ # import_repository("nfs-file06", "gitlab/gitlab-ci", "https://gitlab.com/gitlab-org/gitlab-test.git")
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/874
def import_repository(storage, name, url)
@@ -131,8 +131,7 @@ module Gitlab
if is_enabled
repository.gitaly_repository_client.fetch_remote(remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, timeout: git_timeout, prune: prune)
else
- storage_path = Gitlab.config.repositories.storages[repository.storage].legacy_disk_path
- local_fetch_remote(storage_path, repository.relative_path, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, prune: prune)
+ local_fetch_remote(repository.storage, repository.relative_path, remote, ssh_auth: ssh_auth, forced: forced, no_tags: no_tags, prune: prune)
end
end
end
@@ -156,13 +155,13 @@ module Gitlab
end
# Fork repository to new path
- # forked_from_storage - forked-from project's storage path
- # forked_from_disk_path - project disk path
- # forked_to_storage - forked-to project's storage path
- # forked_to_disk_path - forked project disk path
+ # forked_from_storage - forked-from project's storage name
+ # forked_from_disk_path - project disk relative path
+ # forked_to_storage - forked-to project's storage name
+ # forked_to_disk_path - forked project disk relative path
#
# Ex.
- # fork_repository("/path/to/forked_from/storage", "gitlab/gitlab-ci", "/path/to/forked_to/storage", "new-namespace/gitlab-ci")
+ # fork_repository("nfs-file06", "gitlab/gitlab-ci", "nfs-file07", "new-namespace/gitlab-ci")
#
# 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)
@@ -420,16 +419,16 @@ module Gitlab
private
- def gitlab_projects(shard_path, disk_path)
+ def gitlab_projects(shard_name, disk_path)
Gitlab::Git::GitlabProjects.new(
- shard_path,
+ shard_name,
disk_path,
global_hooks_path: Gitlab.config.gitlab_shell.hooks_path,
logger: Rails.logger
)
end
- def local_fetch_remote(storage_path, repository_relative_path, remote, ssh_auth: nil, forced: false, no_tags: false, prune: true)
+ def local_fetch_remote(storage_name, repository_relative_path, remote, ssh_auth: nil, forced: false, no_tags: false, prune: true)
vars = { force: forced, tags: !no_tags, prune: prune }
if ssh_auth&.ssh_import?
@@ -442,7 +441,7 @@ module Gitlab
end
end
- cmd = gitlab_projects(storage_path, repository_relative_path)
+ cmd = gitlab_projects(storage_name, repository_relative_path)
success = cmd.fetch_remote(remote, git_timeout, vars)
diff --git a/lib/gitlab/sidekiq_logging/json_formatter.rb b/lib/gitlab/sidekiq_logging/json_formatter.rb
new file mode 100644
index 00000000000..98f8222fd03
--- /dev/null
+++ b/lib/gitlab/sidekiq_logging/json_formatter.rb
@@ -0,0 +1,21 @@
+module Gitlab
+ module SidekiqLogging
+ class JSONFormatter
+ def call(severity, timestamp, progname, data)
+ output = {
+ severity: severity,
+ time: timestamp.utc.iso8601(3)
+ }
+
+ case data
+ when String
+ output[:message] = data
+ when Hash
+ output.merge!(data)
+ end
+
+ output.to_json + "\n"
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/sidekiq_logging/structured_logger.rb b/lib/gitlab/sidekiq_logging/structured_logger.rb
new file mode 100644
index 00000000000..9a89ae70b98
--- /dev/null
+++ b/lib/gitlab/sidekiq_logging/structured_logger.rb
@@ -0,0 +1,96 @@
+module Gitlab
+ module SidekiqLogging
+ class StructuredLogger
+ START_TIMESTAMP_FIELDS = %w[created_at enqueued_at].freeze
+ DONE_TIMESTAMP_FIELDS = %w[started_at retried_at failed_at completed_at].freeze
+
+ def call(job, queue)
+ started_at = current_time
+ base_payload = parse_job(job)
+
+ Sidekiq.logger.info log_job_start(started_at, base_payload)
+
+ yield
+
+ Sidekiq.logger.info log_job_done(started_at, base_payload)
+ rescue => job_exception
+ Sidekiq.logger.warn log_job_done(started_at, base_payload, job_exception)
+
+ raise
+ end
+
+ private
+
+ def base_message(payload)
+ "#{payload['class']} JID-#{payload['jid']}"
+ end
+
+ def log_job_start(started_at, payload)
+ payload['message'] = "#{base_message(payload)}: start"
+ payload['job_status'] = 'start'
+
+ payload
+ end
+
+ def log_job_done(started_at, payload, job_exception = nil)
+ payload = payload.dup
+ payload['duration'] = elapsed(started_at)
+ payload['completed_at'] = Time.now.utc
+
+ message = base_message(payload)
+
+ if job_exception
+ payload['message'] = "#{message}: fail: #{payload['duration']} sec"
+ payload['job_status'] = 'fail'
+ payload['error_message'] = job_exception.message
+ payload['error'] = job_exception.class
+ payload['error_backtrace'] = backtrace_cleaner.clean(job_exception.backtrace)
+ else
+ payload['message'] = "#{message}: done: #{payload['duration']} sec"
+ payload['job_status'] = 'done'
+ end
+
+ convert_to_iso8601(payload, DONE_TIMESTAMP_FIELDS)
+
+ payload
+ end
+
+ def parse_job(job)
+ job = job.dup
+
+ # Add process id params
+ job['pid'] = ::Process.pid
+
+ job.delete('args') unless ENV['SIDEKIQ_LOG_ARGUMENTS']
+
+ convert_to_iso8601(job, START_TIMESTAMP_FIELDS)
+
+ job
+ end
+
+ def convert_to_iso8601(payload, keys)
+ keys.each do |key|
+ payload[key] = format_time(payload[key]) if payload[key]
+ end
+ end
+
+ def elapsed(start)
+ (current_time - start).round(3)
+ end
+
+ def current_time
+ Gitlab::Metrics::System.monotonic_time
+ end
+
+ def backtrace_cleaner
+ @backtrace_cleaner ||= ActiveSupport::BacktraceCleaner.new
+ end
+
+ def format_time(timestamp)
+ return timestamp if timestamp.is_a?(String)
+
+ Time.at(timestamp).utc.iso8601(3)
+ end
+ end
+ end
+end
diff --git a/lib/tasks/gitlab/two_factor.rake b/lib/tasks/gitlab/two_factor.rake
index 7728c485e8d..6b22499a5c8 100644
--- a/lib/tasks/gitlab/two_factor.rake
+++ b/lib/tasks/gitlab/two_factor.rake
@@ -1,7 +1,7 @@
namespace :gitlab do
namespace :two_factor do
desc "GitLab | Disable Two-factor authentication (2FA) for all users"
- task disable_for_all_users: :environment do
+ task disable_for_all_users: :gitlab_environment do
scope = User.with_two_factor
count = scope.count
diff --git a/lib/tasks/test.rake b/lib/tasks/test.rake
index 3e01f91d32c..b52af81fc16 100644
--- a/lib/tasks/test.rake
+++ b/lib/tasks/test.rake
@@ -4,8 +4,3 @@ desc "GitLab | Run all tests"
task :test do
Rake::Task["gitlab:test"].invoke
end
-
-unless Rails.env.production?
- desc "GitLab | Run all tests on CI with simplecov"
- task test_ci: [:rubocop, :brakeman, :karma, :spinach, :spec]
-end