summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorGrzegorz Bizon <grzegorz@gitlab.com>2018-02-22 12:09:27 +0000
committerGrzegorz Bizon <grzegorz@gitlab.com>2018-02-22 12:09:27 +0000
commit011ddb51b40897bc13a75d78c9e992f559cbde48 (patch)
treed2f25aa76ab1466ecca82d2cf07e3594b8d7addc /lib
parenta75cce1febf0403d66631841fff3bfbeefbfe6e3 (diff)
parenteb421c88ee2a57a437b9b14ba7447a04720354ac (diff)
downloadgitlab-ce-011ddb51b40897bc13a75d78c9e992f559cbde48.tar.gz
Merge branch 'master' into 'backstage/gb/build-stages-catch-up-migration'
# Conflicts: # db/schema.rb
Diffstat (limited to 'lib')
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/commits.rb5
-rw-r--r--lib/api/entities.rb7
-rw-r--r--lib/api/pages_domains.rb10
-rw-r--r--lib/api/project_import.rb69
-rw-r--r--lib/api/projects.rb1
-rw-r--r--lib/gitlab/asciidoc.rb3
-rw-r--r--lib/gitlab/background_migration/populate_untracked_uploads.rb160
-rw-r--r--lib/gitlab/background_migration/populate_untracked_uploads_dependencies.rb201
-rw-r--r--lib/gitlab/checks/change_access.rb7
-rw-r--r--lib/gitlab/checks/commit_check.rb4
-rw-r--r--lib/gitlab/git/commit.rb2
-rw-r--r--lib/gitlab/git/repository.rb37
-rw-r--r--lib/gitlab/git_access.rb6
-rw-r--r--lib/gitlab/git_access_wiki.rb6
-rw-r--r--lib/gitlab/gitaly_client/repository_service.rb17
-rw-r--r--lib/gitlab/github_import/importer/repository_importer.rb1
-rw-r--r--lib/gitlab/gpg/commit.rb4
-rw-r--r--lib/gitlab/metrics/sidekiq_metrics_exporter.rb2
-rw-r--r--lib/gitlab/metrics/transaction.rb5
-rw-r--r--lib/gitlab/query_limiting/active_support_subscriber.rb6
-rw-r--r--lib/gitlab/setup_helper.rb2
-rw-r--r--lib/gitlab/ssh_public_key.rb28
-rw-r--r--lib/tasks/gitlab/gitaly.rake4
-rw-r--r--lib/tasks/lint.rake49
25 files changed, 446 insertions, 191 deletions
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/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
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 03abc1b95c5..45c737c6c29 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -91,6 +91,13 @@ module API
expose :created_at
end
+ class ProjectImportStatus < ProjectIdentity
+ expose :import_status
+
+ # 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
include ::API::ProjectsRelationBuilder
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
diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb
new file mode 100644
index 00000000000..a509c1f32c1
--- /dev/null
+++ b/lib/api/project_import.rb
@@ -0,0 +1,69 @@
+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]['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: 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 current user's 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
+ validate_file!
+
+ Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-ce/issues/42437')
+
+ namespace = if import_params[:namespace]
+ find_namespace!(import_params[:namespace])
+ else
+ current_user.namespace
+ end
+
+ 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?
+
+ present project, with: Entities::ProjectImportStatus
+ end
+
+ params do
+ 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
+ present user_project, with: Entities::ProjectImportStatus
+ end
+ end
+ end
+end
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,
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.
diff --git a/lib/gitlab/background_migration/populate_untracked_uploads.rb b/lib/gitlab/background_migration/populate_untracked_uploads.rb
index ee55fabd6f0..9232f20a063 100644
--- a/lib/gitlab/background_migration/populate_untracked_uploads.rb
+++ b/lib/gitlab/background_migration/populate_untracked_uploads.rb
@@ -5,157 +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
- # 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 = 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
-
- # 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?
- 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
@@ -165,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)
@@ -197,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)
@@ -229,7 +83,7 @@ module Gitlab
end
ids.each do |model_type, model_ids|
- model_class = Object.const_get(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
@@ -249,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
new file mode 100644
index 00000000000..a2c5acbde71
--- /dev/null
+++ b/lib/gitlab/background_migration/populate_untracked_uploads_dependencies.rb
@@ -0,0 +1,201 @@
+# frozen_string_literal: true
+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'
+ 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
diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb
index 521680b8708..3ce5f807989 100644
--- a/lib/gitlab/checks/change_access.rb
+++ b/lib/gitlab/checks/change_access.rb
@@ -121,6 +121,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
@@ -139,6 +140,10 @@ module Gitlab
private
+ def should_run_commit_validations?
+ commit_check.validate_lfs_file_locks?
+ end
+
def updated_from_web?
protocol == 'web'
end
@@ -176,7 +181,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
diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb
index d95561fe1b2..ae27a138b7c 100644
--- a/lib/gitlab/git/commit.rb
+++ b/lib/gitlab/git/commit.rb
@@ -508,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
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 5f014e43c6f..e3cbf017e55 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)
@@ -1349,7 +1355,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 +1365,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 +1464,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?('/')
+
+ # 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)
- return [] unless names.respond_to?(:split)
+ return [] unless code.zero?
- names = names.split("\n").map(&:strip)
+ refs = []
+ left_slice_count = refs_prefix.length
+ names.lines.each do |line|
+ next unless line.start_with?(refs_prefix)
- names.each do |name|
- name.slice! '* '
+ refs << line.rstrip[left_slice_count..-1]
end
- names
+ refs
end
def rugged_write_config(full_path:)
@@ -2188,13 +2200,14 @@ 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
# 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
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
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,
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
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
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
diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb
index 45b9e14ba55..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,11 +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 if use_feature_flag
if type == :gauge
multiprocess_mode :livesum
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
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/gitlab/ssh_public_key.rb b/lib/gitlab/ssh_public_key.rb
index 89ca1298120..6f63ea91ae8 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?
+ SSHKey.valid_ssh_public_key?(key_text)
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
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."
diff --git a/lib/tasks/lint.rake b/lib/tasks/lint.rake
index 3ab406eff2c..fe5032cae18 100644
--- a/lib/tasks/lint.rake
+++ b/lib/tasks/lint.rake
@@ -16,5 +16,54 @@ unless Rails.env.production?
task :javascript do
Rake::Task['eslint'].invoke
end
+
+ desc "GitLab | lint | Run several lint checks"
+ task :all do
+ status = 0
+
+ %w[
+ config_lint
+ haml_lint
+ scss_lint
+ flay
+ gettext:lint
+ lint:static_verification
+ ].each do |task|
+ 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)
+ end
end
end