Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKushal Pandya <kushalspandya@gmail.com>2017-04-06 12:46:50 +0300
committerKushal Pandya <kushalspandya@gmail.com>2017-04-06 12:46:50 +0300
commit18506d4b8b8bc780b3b1e4c61339af38b5c49bb2 (patch)
tree6aab0c83abe14064433c326996ccbe8097495454 /lib/gitlab
parentcd5b36d04e79ed8fcd649127e0d47e09ec325242 (diff)
parent49bdd8d63b577f079cdc47f7dd10ba83c677771a (diff)
Merge branch 'master' into '18471-restrict-tag-pushes-protected-tags'
# Conflicts: # app/assets/javascripts/dispatcher.js # app/assets/stylesheets/pages/projects.scss
Diffstat (limited to 'lib/gitlab')
-rw-r--r--lib/gitlab/bitbucket_import/importer.rb9
-rw-r--r--lib/gitlab/ci/build/step.rb9
-rw-r--r--lib/gitlab/ci/status/canceled.rb4
-rw-r--r--lib/gitlab/ci/status/core.rb4
-rw-r--r--lib/gitlab/ci/status/created.rb4
-rw-r--r--lib/gitlab/ci/status/failed.rb4
-rw-r--r--lib/gitlab/ci/status/manual.rb4
-rw-r--r--lib/gitlab/ci/status/pending.rb4
-rw-r--r--lib/gitlab/ci/status/running.rb4
-rw-r--r--lib/gitlab/ci/status/skipped.rb4
-rw-r--r--lib/gitlab/ci/status/success.rb4
-rw-r--r--lib/gitlab/ee_compat_check.rb299
-rw-r--r--lib/gitlab/etag_caching/middleware.rb16
-rw-r--r--lib/gitlab/etag_caching/store.rb2
-rw-r--r--lib/gitlab/git.rb2
-rw-r--r--lib/gitlab/git/repository.rb79
-rw-r--r--lib/gitlab/git/tree.rb2
-rw-r--r--lib/gitlab/gitaly_client.rb69
-rw-r--r--lib/gitlab/gitaly_client/commit.rb20
-rw-r--r--lib/gitlab/gitaly_client/notifications.rb12
-rw-r--r--lib/gitlab/gitaly_client/ref.rb35
-rw-r--r--lib/gitlab/gitaly_client/util.rb13
-rw-r--r--lib/gitlab/github_import/branch_formatter.rb8
-rw-r--r--lib/gitlab/github_import/importer.rb2
-rw-r--r--lib/gitlab/github_import/pull_request_formatter.rb36
-rw-r--r--lib/gitlab/import_export/hash_util.rb25
-rw-r--r--lib/gitlab/import_export/import_export.yml2
-rw-r--r--lib/gitlab/import_export/importer.rb2
-rw-r--r--lib/gitlab/import_export/merge_request_parser.rb41
-rw-r--r--lib/gitlab/import_export/project_tree_restorer.rb2
-rw-r--r--lib/gitlab/import_export/relation_factory.rb17
-rw-r--r--lib/gitlab/ldap/config.rb4
-rw-r--r--lib/gitlab/o_auth/user.rb6
-rw-r--r--lib/gitlab/polling_interval.rb22
-rw-r--r--lib/gitlab/project_search_results.rb2
-rw-r--r--lib/gitlab/repo_path.rb23
-rw-r--r--lib/gitlab/search_results.rb21
-rw-r--r--lib/gitlab/shell.rb27
-rw-r--r--lib/gitlab/testing/request_blocker_middleware.rb61
-rw-r--r--lib/gitlab/uploads_transfer.rb2
-rw-r--r--lib/gitlab/url_sanitizer.rb6
-rw-r--r--lib/gitlab/workhorse.rb34
42 files changed, 736 insertions, 210 deletions
diff --git a/lib/gitlab/bitbucket_import/importer.rb b/lib/gitlab/bitbucket_import/importer.rb
index 44323b47dca..f4efa20374a 100644
--- a/lib/gitlab/bitbucket_import/importer.rb
+++ b/lib/gitlab/bitbucket_import/importer.rb
@@ -130,8 +130,13 @@ module Gitlab
end
def create_labels
- LABELS.each do |label|
- @labels[label[:title]] = project.labels.create!(label)
+ LABELS.each do |label_params|
+ label = ::Labels::CreateService.new(label_params).execute(project: project)
+ if label.valid?
+ @labels[label_params[:title]] = label
+ else
+ raise "Failed to create label \"#{label_params[:title]}\" for project \"#{project.name_with_namespace}\""
+ end
end
end
diff --git a/lib/gitlab/ci/build/step.rb b/lib/gitlab/ci/build/step.rb
index 1877429ac46..ee034d9cc56 100644
--- a/lib/gitlab/ci/build/step.rb
+++ b/lib/gitlab/ci/build/step.rb
@@ -7,13 +7,12 @@ module Gitlab
WHEN_ALWAYS = 'always'.freeze
attr_reader :name
- attr_writer :script
- attr_accessor :timeout, :when, :allow_failure
+ attr_accessor :script, :timeout, :when, :allow_failure
class << self
def from_commands(job)
self.new(:script).tap do |step|
- step.script = job.commands
+ step.script = job.commands.split("\n")
step.timeout = job.timeout
step.when = WHEN_ON_SUCCESS
end
@@ -36,10 +35,6 @@ module Gitlab
@name = name
@allow_failure = false
end
-
- def script
- @script.split("\n")
- end
end
end
end
diff --git a/lib/gitlab/ci/status/canceled.rb b/lib/gitlab/ci/status/canceled.rb
index dd6d99e9075..97c121ce7b9 100644
--- a/lib/gitlab/ci/status/canceled.rb
+++ b/lib/gitlab/ci/status/canceled.rb
@@ -13,6 +13,10 @@ module Gitlab
def icon
'icon_status_canceled'
end
+
+ def favicon
+ 'favicon_status_canceled'
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/core.rb b/lib/gitlab/ci/status/core.rb
index 3dd2b9e01f6..d4fd83b93f8 100644
--- a/lib/gitlab/ci/status/core.rb
+++ b/lib/gitlab/ci/status/core.rb
@@ -18,6 +18,10 @@ module Gitlab
raise NotImplementedError
end
+ def favicon
+ raise NotImplementedError
+ end
+
def label
raise NotImplementedError
end
diff --git a/lib/gitlab/ci/status/created.rb b/lib/gitlab/ci/status/created.rb
index 6596d7e01ca..0721bf6ec7c 100644
--- a/lib/gitlab/ci/status/created.rb
+++ b/lib/gitlab/ci/status/created.rb
@@ -13,6 +13,10 @@ module Gitlab
def icon
'icon_status_created'
end
+
+ def favicon
+ 'favicon_status_created'
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/failed.rb b/lib/gitlab/ci/status/failed.rb
index c5b5e3203ad..cb75e9383a8 100644
--- a/lib/gitlab/ci/status/failed.rb
+++ b/lib/gitlab/ci/status/failed.rb
@@ -13,6 +13,10 @@ module Gitlab
def icon
'icon_status_failed'
end
+
+ def favicon
+ 'favicon_status_failed'
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/manual.rb b/lib/gitlab/ci/status/manual.rb
index 5f28521901d..f8f6c2903ba 100644
--- a/lib/gitlab/ci/status/manual.rb
+++ b/lib/gitlab/ci/status/manual.rb
@@ -13,6 +13,10 @@ module Gitlab
def icon
'icon_status_manual'
end
+
+ def favicon
+ 'favicon_status_manual'
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/pending.rb b/lib/gitlab/ci/status/pending.rb
index d30f35a59a2..f40cc1314dc 100644
--- a/lib/gitlab/ci/status/pending.rb
+++ b/lib/gitlab/ci/status/pending.rb
@@ -13,6 +13,10 @@ module Gitlab
def icon
'icon_status_pending'
end
+
+ def favicon
+ 'favicon_status_pending'
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/running.rb b/lib/gitlab/ci/status/running.rb
index 2aba3c373c7..1237cd47dc8 100644
--- a/lib/gitlab/ci/status/running.rb
+++ b/lib/gitlab/ci/status/running.rb
@@ -13,6 +13,10 @@ module Gitlab
def icon
'icon_status_running'
end
+
+ def favicon
+ 'favicon_status_running'
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/skipped.rb b/lib/gitlab/ci/status/skipped.rb
index 16282aefd03..28005d91503 100644
--- a/lib/gitlab/ci/status/skipped.rb
+++ b/lib/gitlab/ci/status/skipped.rb
@@ -13,6 +13,10 @@ module Gitlab
def icon
'icon_status_skipped'
end
+
+ def favicon
+ 'favicon_status_skipped'
+ end
end
end
end
diff --git a/lib/gitlab/ci/status/success.rb b/lib/gitlab/ci/status/success.rb
index c09c5f006e3..88f7758a270 100644
--- a/lib/gitlab/ci/status/success.rb
+++ b/lib/gitlab/ci/status/success.rb
@@ -13,6 +13,10 @@ module Gitlab
def icon
'icon_status_success'
end
+
+ def favicon
+ 'favicon_status_success'
+ end
end
end
end
diff --git a/lib/gitlab/ee_compat_check.rb b/lib/gitlab/ee_compat_check.rb
index e0fdf3f3d64..496ee0bdcb0 100644
--- a/lib/gitlab/ee_compat_check.rb
+++ b/lib/gitlab/ee_compat_check.rb
@@ -5,35 +5,44 @@ module Gitlab
CE_REPO = 'https://gitlab.com/gitlab-org/gitlab-ce.git'.freeze
EE_REPO = 'https://gitlab.com/gitlab-org/gitlab-ee.git'.freeze
CHECK_DIR = Rails.root.join('ee_compat_check')
- MAX_FETCH_DEPTH = 500
IGNORED_FILES_REGEX = /(VERSION|CHANGELOG\.md:\d+)/.freeze
-
- attr_reader :repo_dir, :patches_dir, :ce_repo, :ce_branch
+ PLEASE_READ_THIS_BANNER = %Q{
+ ============================================================
+ ===================== PLEASE READ THIS =====================
+ ============================================================
+ }.freeze
+ THANKS_FOR_READING_BANNER = %Q{
+ ============================================================
+ ==================== THANKS FOR READING ====================
+ ============================================================\n
+ }.freeze
+
+ attr_reader :ee_repo_dir, :patches_dir, :ce_repo, :ce_branch, :ee_branch_found
+ attr_reader :failed_files
def initialize(branch:, ce_repo: CE_REPO)
- @repo_dir = CHECK_DIR.join('repo')
+ @ee_repo_dir = CHECK_DIR.join('ee-repo')
@patches_dir = CHECK_DIR.join('patches')
@ce_branch = branch
@ce_repo = ce_repo
end
def check
- ensure_ee_repo
ensure_patches_dir
-
generate_patch(ce_branch, ce_patch_full_path)
- Dir.chdir(repo_dir) do
- step("In the #{repo_dir} directory")
+ ensure_ee_repo
+ Dir.chdir(ee_repo_dir) do
+ step("In the #{ee_repo_dir} directory")
status = catch(:halt_check) do
ce_branch_compat_check!
- delete_ee_branch_locally!
+ delete_ee_branches_locally!
ee_branch_presence_check!
ee_branch_compat_check!
end
- delete_ee_branch_locally!
+ delete_ee_branches_locally!
if status.nil?
true
@@ -46,11 +55,13 @@ module Gitlab
private
def ensure_ee_repo
- if Dir.exist?(repo_dir)
- step("#{repo_dir} already exists")
+ if Dir.exist?(ee_repo_dir)
+ step("#{ee_repo_dir} already exists")
else
- cmd = %W[git clone --branch master --single-branch --depth 200 #{EE_REPO} #{repo_dir}]
- step("Cloning #{EE_REPO} into #{repo_dir}", cmd)
+ step(
+ "Cloning #{EE_REPO} into #{ee_repo_dir}",
+ %W[git clone --branch master --single-branch --depth=200 #{EE_REPO} #{ee_repo_dir}]
+ )
end
end
@@ -61,23 +72,18 @@ module Gitlab
def generate_patch(branch, patch_path)
FileUtils.rm(patch_path, force: true)
- depth = 0
- loop do
- depth += 50
- cmd = %W[git fetch --depth #{depth} origin --prune +refs/heads/master:refs/remotes/origin/master]
- Gitlab::Popen.popen(cmd)
- _, status = Gitlab::Popen.popen(%w[git merge-base FETCH_HEAD HEAD])
+ find_merge_base_with_master(branch: branch)
- raise "#{branch} is too far behind master, please rebase it!" if depth >= MAX_FETCH_DEPTH
- break if status.zero?
- end
+ step(
+ "Generating the patch against origin/master in #{patch_path}",
+ %w[git format-patch origin/master --stdout]
+ ) do |output, status|
+ throw(:halt_check, :ko) unless status.zero?
- step("Generating the patch against master in #{patch_path}")
- output, status = Gitlab::Popen.popen(%w[git format-patch FETCH_HEAD --stdout])
- throw(:halt_check, :ko) unless status.zero?
+ File.write(patch_path, output)
- File.write(patch_path, output)
- throw(:halt_check, :ko) unless File.exist?(patch_path)
+ throw(:halt_check, :ko) unless File.exist?(patch_path)
+ end
end
def ce_branch_compat_check!
@@ -88,9 +94,17 @@ module Gitlab
end
def ee_branch_presence_check!
- status = step("Fetching origin/#{ee_branch}", %W[git fetch origin #{ee_branch}])
+ _, status = step("Fetching origin/#{ee_branch_prefix}", %W[git fetch origin #{ee_branch_prefix}])
- unless status.zero?
+ if status.zero?
+ @ee_branch_found = ee_branch_prefix
+ else
+ _, status = step("Fetching origin/#{ee_branch_suffix}", %W[git fetch origin #{ee_branch_suffix}])
+ end
+
+ if status.zero?
+ @ee_branch_found = ee_branch_suffix
+ else
puts
puts ce_branch_doesnt_apply_cleanly_and_no_ee_branch_msg
@@ -99,9 +113,9 @@ module Gitlab
end
def ee_branch_compat_check!
- step("Checking out origin/#{ee_branch}", %W[git checkout -b #{ee_branch} FETCH_HEAD])
+ step("Checking out origin/#{ee_branch_found}", %W[git checkout -b #{ee_branch_found} FETCH_HEAD])
- generate_patch(ee_branch, ee_patch_full_path)
+ generate_patch(ee_branch_found, ee_patch_full_path)
unless check_patch(ee_patch_full_path).zero?
puts
@@ -111,41 +125,77 @@ module Gitlab
end
puts
- puts applies_cleanly_msg(ee_branch)
+ puts applies_cleanly_msg(ee_branch_found)
end
def check_patch(patch_path)
step("Checking out master", %w[git checkout master])
- step("Reseting to latest master", %w[git reset --hard origin/master])
-
- step("Checking if #{patch_path} applies cleanly to EE/master")
- output, status = Gitlab::Popen.popen(%W[git apply --check --3way #{patch_path}])
-
- unless status.zero?
- failed_files = output.lines.reduce([]) do |memo, line|
- if line.start_with?('error: patch failed:')
- file = line.sub(/\Aerror: patch failed: /, '')
- memo << file unless file =~ IGNORED_FILES_REGEX
+ step("Resetting to latest master", %w[git reset --hard origin/master])
+ step(
+ "Checking if #{patch_path} applies cleanly to EE/master",
+ %W[git apply --check --3way #{patch_path}]
+ ) do |output, status|
+ unless status.zero?
+ @failed_files = output.lines.reduce([]) do |memo, line|
+ if line.start_with?('error: patch failed:')
+ file = line.sub(/\Aerror: patch failed: /, '')
+ memo << file unless file =~ IGNORED_FILES_REGEX
+ end
+ memo
end
- memo
+
+ status = 0 if failed_files.empty?
end
- if failed_files.empty?
- status = 0
- else
- puts "\nConflicting files:"
- failed_files.each do |file|
- puts " - #{file}"
- end
+ status
+ end
+ end
+
+ def delete_ee_branches_locally!
+ command(%w[git checkout master])
+ command(%W[git branch --delete --force #{ee_branch_prefix}])
+ command(%W[git branch --delete --force #{ee_branch_suffix}])
+ end
+
+ def merge_base_found?
+ step(
+ "Finding merge base with master",
+ %w[git merge-base origin/master HEAD]
+ ) do |output, status|
+ if status.zero?
+ puts "Merge base was found: #{output}"
+ true
end
end
+ end
+
+ def find_merge_base_with_master(branch:)
+ return if merge_base_found?
+
+ # Start with (Math.exp(3).to_i = 20) until (Math.exp(6).to_i = 403)
+ # In total we go (20 + 54 + 148 + 403 = 625) commits deeper
+ depth = 20
+ success =
+ (3..6).any? do |factor|
+ depth += Math.exp(factor).to_i
+ # Repository is initially cloned with a depth of 20 so we need to fetch
+ # deeper in the case the branch has more than 20 commits on top of master
+ fetch(branch: branch, depth: depth)
+ fetch(branch: 'master', depth: depth)
+
+ merge_base_found?
+ end
- status
+ raise "\n#{branch} is too far behind master, please rebase it!\n" unless success
end
- def delete_ee_branch_locally!
- command(%w[git checkout master])
- step("Deleting the local #{ee_branch} branch", %W[git branch -D #{ee_branch}])
+ def fetch(branch:, depth:)
+ step(
+ "Fetching deeper...",
+ %W[git fetch --depth=#{depth} --prune origin +refs/heads/#{branch}:refs/remotes/origin/#{branch}]
+ ) do |output, status|
+ raise "Fetch failed: #{output}" unless status.zero?
+ end
end
def ce_patch_name
@@ -156,12 +206,16 @@ module Gitlab
@ce_patch_full_path ||= patches_dir.join(ce_patch_name)
end
- def ee_branch
- @ee_branch ||= "#{ce_branch}-ee"
+ def ee_branch_suffix
+ @ee_branch_suffix ||= "#{ce_branch}-ee"
+ end
+
+ def ee_branch_prefix
+ @ee_branch_prefix ||= "ee-#{ce_branch}"
end
def ee_patch_name
- @ee_patch_name ||= patch_name_from_branch(ee_branch)
+ @ee_patch_name ||= patch_name_from_branch(ee_branch_found)
end
def ee_patch_full_path
@@ -178,98 +232,125 @@ module Gitlab
if cmd
start = Time.now
puts "\n$ #{cmd.join(' ')}"
- status = command(cmd)
- puts "\nFinished in #{Time.now - start} seconds"
- status
+
+ output, status = command(cmd)
+ puts "\n==> Finished in #{Time.now - start} seconds"
+
+ if block_given?
+ yield(output, status)
+ else
+ [output, status]
+ end
end
end
def command(cmd)
- output, status = Gitlab::Popen.popen(cmd)
- puts output
-
- status
+ Gitlab::Popen.popen(cmd)
end
def applies_cleanly_msg(branch)
- <<-MSG.strip_heredoc
- =================================================================
+ %Q{
+ #{PLEASE_READ_THIS_BANNER}
🎉 Congratulations!! 🎉
- The #{branch} branch applies cleanly to EE/master!
+ The `#{branch}` branch applies cleanly to EE/master!
- Much ❤️!!
- =================================================================\n
- MSG
+ Much ❤️! For more information, see
+ https://docs.gitlab.com/ce/development/limit_ee_conflicts.html#check-the-rake-ee_compat_check-in-your-merge-requests
+ #{THANKS_FOR_READING_BANNER}
+ }
end
def ce_branch_doesnt_apply_cleanly_and_no_ee_branch_msg
- <<-MSG.strip_heredoc
- =================================================================
+ %Q{
+ #{PLEASE_READ_THIS_BANNER}
💥 Oh no! 💥
- The #{ce_branch} branch does not apply cleanly to the current
- EE/master, and no #{ee_branch} branch was found in the EE repository.
+ The `#{ce_branch}` branch does not apply cleanly to the current
+ EE/master, and no `#{ee_branch_prefix}` or `#{ee_branch_suffix}` branch
+ was found in the EE repository.
- Please create a #{ee_branch} branch that includes changes from
- #{ce_branch} but also specific changes than can be applied cleanly
- to EE/master.
+ #{conflicting_files_msg}
+
+ We advise you to create a `#{ee_branch_prefix}` or `#{ee_branch_suffix}`
+ branch that includes changes from `#{ce_branch}` but also specific changes
+ than can be applied cleanly to EE/master. In some cases, the conflicts
+ are trivial and you can ignore the warning from this job. As always,
+ use your best judgment!
There are different ways to create such branch:
- 1. Create a new branch based on the CE branch and rebase it on top of EE/master
+ 1. Create a new branch from master and cherry-pick your CE commits
# In the EE repo
- $ git fetch #{ce_repo} #{ce_branch}
- $ git checkout -b #{ee_branch} FETCH_HEAD
-
- # You can squash the #{ce_branch} commits into a single "Port of #{ce_branch} to EE" commit
- # before rebasing to limit the conflicts-resolving steps during the rebase
$ git fetch origin
- $ git rebase origin/master
+ $ git checkout -b #{ee_branch_prefix} origin/master
+ $ git fetch #{ce_repo} #{ce_branch}
+ $ git cherry-pick SHA # Repeat for all the commits you want to pick
- At this point you will likely have conflicts.
- Solve them, and continue/finish the rebase.
+ You can squash the `#{ce_branch}` commits into a single "Port of #{ce_branch} to EE" commit.
- You can squash the #{ce_branch} commits into a single "Port of #{ce_branch} to EE".
+ 2. Apply your branch's patch to EE
- 2. Create a new branch from master and cherry-pick your CE commits
+ # In the CE repo
+ $ git fetch origin master
+ $ git format-patch origin/master --stdout > #{ce_branch}.patch
# In the EE repo
- $ git fetch origin
- $ git checkout -b #{ee_branch} origin/master
- $ git fetch #{ce_repo} #{ce_branch}
- $ git cherry-pick SHA # Repeat for all the commits you want to pick
+ $ git fetch origin master
+ $ git checkout -b #{ee_branch_prefix} origin/master
+ $ git apply --3way path/to/#{ce_branch}.patch
+
+ At this point you might have conflicts such as:
- You can squash the #{ce_branch} commits into a single "Port of #{ce_branch} to EE" commit.
+ error: patch failed: lib/gitlab/ee_compat_check.rb:5
+ Falling back to three-way merge...
+ Applied patch to 'lib/gitlab/ee_compat_check.rb' with conflicts.
+ U lib/gitlab/ee_compat_check.rb
- Don't forget to push your branch to #{EE_REPO}:
+ Resolve them, stage the changes and commit them.
+
+ ⚠️ Don't forget to push your branch to gitlab-ee:
# In the EE repo
- $ git push origin #{ee_branch}
+ $ git push origin #{ee_branch_prefix}
+
+ ⚠️ Also, don't forget to create a new merge request on gitlab-ce and
+ cross-link it with the CE merge request.
- You can then retry this failed build, and hopefully it should pass.
+ Once this is done, you can retry this failed build, and it should pass.
- Stay 💪 !
- =================================================================\n
- MSG
+ Stay 💪 ! For more information, see
+ https://docs.gitlab.com/ce/development/limit_ee_conflicts.html#check-the-rake-ee_compat_check-in-your-merge-requests
+ #{THANKS_FOR_READING_BANNER}
+ }
end
def ee_branch_doesnt_apply_cleanly_msg
- <<-MSG.strip_heredoc
- =================================================================
+ %Q{
+ #{PLEASE_READ_THIS_BANNER}
💥 Oh no! 💥
- The #{ce_branch} does not apply cleanly to the current
- EE/master, and even though a #{ee_branch} branch exists in the EE
- repository, it does not apply cleanly either to EE/master!
+ The `#{ce_branch}` does not apply cleanly to the current EE/master, and
+ even though a `#{ee_branch_found}` branch
+ exists in the EE repository, it does not apply cleanly either to
+ EE/master!
+
+ #{conflicting_files_msg}
- Please update the #{ee_branch}, push it again to #{EE_REPO}, and
+ Please update the `#{ee_branch_found}`, push it again to gitlab-ee, and
retry this build.
- Stay 💪 !
- =================================================================\n
- MSG
+ Stay 💪 ! For more information, see
+ https://docs.gitlab.com/ce/development/limit_ee_conflicts.html#check-the-rake-ee_compat_check-in-your-merge-requests
+ #{THANKS_FOR_READING_BANNER}
+ }
+ end
+
+ def conflicting_files_msg
+ failed_files.reduce("The conflicts detected were as follows:\n") do |memo, file|
+ memo << "\n - #{file}"
+ end
end
end
end
diff --git a/lib/gitlab/etag_caching/middleware.rb b/lib/gitlab/etag_caching/middleware.rb
index ffbc6e17dc5..cd4e318033d 100644
--- a/lib/gitlab/etag_caching/middleware.rb
+++ b/lib/gitlab/etag_caching/middleware.rb
@@ -1,9 +1,10 @@
module Gitlab
module EtagCaching
class Middleware
- RESERVED_WORDS = ProjectPathValidator::RESERVED.map { |word| "/#{word}/" }.join('|')
+ RESERVED_WORDS = NamespaceValidator::WILDCARD_ROUTES.map { |word| "/#{word}/" }.join('|')
ROUTE_REGEXP = Regexp.union(
- %r(^(?!.*(#{RESERVED_WORDS})).*/noteable/issue/\d+/notes\z)
+ %r(^(?!.*(#{RESERVED_WORDS})).*/noteable/issue/\d+/notes\z),
+ %r(^(?!.*(#{RESERVED_WORDS})).*/issues/\d+/rendered_title\z)
)
def initialize(app)
@@ -18,8 +19,7 @@ module Gitlab
if_none_match = env['HTTP_IF_NONE_MATCH']
if if_none_match == etag
- Gitlab::Metrics.add_event(:etag_caching_cache_hit)
- [304, { 'ETag' => etag }, ['']]
+ handle_cache_hit(etag)
else
track_cache_miss(if_none_match, cached_value_present)
@@ -52,6 +52,14 @@ module Gitlab
%Q{W/"#{value}"}
end
+ def handle_cache_hit(etag)
+ Gitlab::Metrics.add_event(:etag_caching_cache_hit)
+
+ status_code = Gitlab::PollingInterval.polling_enabled? ? 304 : 429
+
+ [status_code, { 'ETag' => etag }, ['']]
+ end
+
def track_cache_miss(if_none_match, cached_value_present)
if if_none_match.blank?
Gitlab::Metrics.add_event(:etag_caching_header_missing)
diff --git a/lib/gitlab/etag_caching/store.rb b/lib/gitlab/etag_caching/store.rb
index 9532e432f78..0039fc01c8f 100644
--- a/lib/gitlab/etag_caching/store.rb
+++ b/lib/gitlab/etag_caching/store.rb
@@ -1,7 +1,7 @@
module Gitlab
module EtagCaching
class Store
- EXPIRY_TIME = 10.minutes
+ EXPIRY_TIME = 20.minutes
REDIS_NAMESPACE = 'etag:'.freeze
def get(key)
diff --git a/lib/gitlab/git.rb b/lib/gitlab/git.rb
index d3df3f1bca1..936606152e9 100644
--- a/lib/gitlab/git.rb
+++ b/lib/gitlab/git.rb
@@ -4,6 +4,8 @@ module Gitlab
TAG_REF_PREFIX = "refs/tags/".freeze
BRANCH_REF_PREFIX = "refs/heads/".freeze
+ CommandError = Class.new(StandardError)
+
class << self
def ref_name(ref)
ref.sub(/\Arefs\/(tags|heads)\//, '')
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 2187dd70ff4..2e4314932c8 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -25,9 +25,13 @@ module Gitlab
# 'path' must be the path to a _bare_ git repository, e.g.
# /path/to/my-repo.git
- def initialize(path)
- @path = path
- @name = path.split("/").last
+ def initialize(repository_storage, relative_path)
+ @repository_storage = repository_storage
+ @relative_path = relative_path
+
+ storage_path = Gitlab.config.repositories.storages[@repository_storage]['path']
+ @path = File.join(storage_path, @relative_path)
+ @name = @relative_path.split("/").last
@attributes = Gitlab::Git::Attributes.new(path)
end
@@ -37,7 +41,15 @@ module Gitlab
# Default branch in the repository
def root_ref
- @root_ref ||= discover_default_branch
+ @root_ref ||= Gitlab::GitalyClient.migrate(:root_ref) do |is_enabled|
+ if is_enabled
+ gitaly_ref_client.default_branch_name
+ else
+ discover_default_branch
+ end
+ end
+ rescue GRPC::BadStatus => e
+ raise CommandError.new(e)
end
# Alias to old method for compatibility
@@ -54,7 +66,15 @@ module Gitlab
# Returns an Array of branch names
# sorted by name ASC
def branch_names
- branches.map(&:name)
+ Gitlab::GitalyClient.migrate(:branch_names) do |is_enabled|
+ if is_enabled
+ gitaly_ref_client.branch_names
+ else
+ branches.map(&:name)
+ end
+ end
+ rescue GRPC::BadStatus => e
+ raise CommandError.new(e)
end
# Returns an Array of Branches
@@ -107,7 +127,15 @@ module Gitlab
# Returns an Array of tag names
def tag_names
- rugged.tags.map { |t| t.name }
+ Gitlab::GitalyClient.migrate(:tag_names) do |is_enabled|
+ if is_enabled
+ gitaly_ref_client.tag_names
+ else
+ rugged.tags.map { |t| t.name }
+ end
+ end
+ rescue GRPC::BadStatus => e
+ raise CommandError.new(e)
end
# Returns an Array of Tags
@@ -320,7 +348,7 @@ module Gitlab
def log_by_walk(sha, options)
walk_options = {
show: sha,
- sort: Rugged::SORT_DATE,
+ sort: Rugged::SORT_NONE,
limit: options[:limit],
offset: options[:offset]
}
@@ -346,7 +374,12 @@ module Gitlab
cmd << "--after=#{options[:after].iso8601}" if options[:after]
cmd << "--before=#{options[:before].iso8601}" if options[:before]
cmd << sha
- cmd += %W[-- #{options[:path]}] if options[:path].present?
+
+ # :path can be a string or an array of strings
+ if options[:path].present?
+ cmd << '--'
+ cmd += Array(options[:path])
+ end
raw_output = IO.popen(cmd) { |io| io.read }
lines = offset_in_ruby ? raw_output.lines.drop(offset) : raw_output.lines
@@ -382,7 +415,7 @@ module Gitlab
# a detailed list of valid arguments.
def commits_between(from, to)
walker = Rugged::Walker.new(rugged)
- walker.sorting(Rugged::SORT_DATE | Rugged::SORT_REVERSE)
+ walker.sorting(Rugged::SORT_NONE | Rugged::SORT_REVERSE)
sha_from = sha_from_ref(from)
sha_to = sha_from_ref(to)
@@ -406,6 +439,11 @@ module Gitlab
rugged.merge_base(from, to)
end
+ # Returns true is +from+ is direct ancestor to +to+, otherwise false
+ def is_ancestor?(from, to)
+ Gitlab::GitalyClient::Commit.is_ancestor(self, from, to)
+ end
+
# Return an array of Diff objects that represent the diff
# between +from+ and +to+. See Diff::filter_diff_options for the allowed
# diff options. The +options+ hash can also include :break_rewrites to
@@ -460,7 +498,7 @@ module Gitlab
if actual_options[:order] == :topo
walker.sorting(Rugged::SORT_TOPO)
else
- walker.sorting(Rugged::SORT_DATE)
+ walker.sorting(Rugged::SORT_NONE)
end
commits = []
@@ -828,23 +866,6 @@ module Gitlab
Rugged::Commit.create(rugged, actual_options)
end
- def commits_since(from_date)
- walker = Rugged::Walker.new(rugged)
- walker.sorting(Rugged::SORT_DATE | Rugged::SORT_REVERSE)
-
- rugged.references.each("refs/heads/*") do |ref|
- walker.push(ref.target_id)
- end
-
- commits = []
- walker.each do |commit|
- break if commit.author[:time].to_date < from_date
- commits.push(commit)
- end
-
- commits
- end
-
AUTOCRLF_VALUES = {
"true" => true,
"false" => false,
@@ -1209,6 +1230,10 @@ module Gitlab
diff.find_similar!(break_rewrites: break_rewrites)
diff.each_patch
end
+
+ def gitaly_ref_client
+ @gitaly_ref_client ||= Gitlab::GitalyClient::Ref.new(@repository_storage, @relative_path)
+ end
end
end
end
diff --git a/lib/gitlab/git/tree.rb b/lib/gitlab/git/tree.rb
index f7450e8b58f..b722d8a9f56 100644
--- a/lib/gitlab/git/tree.rb
+++ b/lib/gitlab/git/tree.rb
@@ -33,7 +33,7 @@ module Gitlab
root_id: root_tree.oid,
name: entry[:name],
type: entry[:type],
- mode: entry[:filemode],
+ mode: entry[:filemode].to_s(8),
path: path ? File.join(path, entry[:name]) : entry[:name],
commit_id: sha,
)
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 5534d4af439..bcdf1b1faa8 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -2,28 +2,62 @@ require 'gitaly'
module Gitlab
module GitalyClient
- def self.gitaly_address
- if Gitlab.config.gitaly.socket_path
- "unix://#{Gitlab.config.gitaly.socket_path}"
+ SERVER_VERSION_FILE = 'GITALY_SERVER_VERSION'.freeze
+
+ # This function is not thread-safe because it updates Hashes in instance variables.
+ def self.configure_channels
+ @addresses = {}
+ @channels = {}
+ Gitlab.config.repositories.storages.each do |name, params|
+ address = params['gitaly_address']
+ unless address.present?
+ raise "storage #{name.inspect} is missing a gitaly_address"
+ end
+
+ unless URI(address).scheme.in?(%w(tcp unix))
+ raise "Unsupported Gitaly address: #{address.inspect}"
+ end
+
+ @addresses[name] = address
+ @channels[name] = new_channel(address)
end
end
- def self.channel
- return @channel if defined?(@channel)
+ def self.new_channel(address)
+ address = address.sub(%r{^tcp://}, '') if URI(address).scheme == 'tcp'
+ # NOTE: When Gitaly runs on a Unix socket, permissions are
+ # handled using the file system and no additional authentication is
+ # required (therefore the :this_channel_is_insecure flag)
+ # TODO: Add authentication support when Gitaly is running on a TCP socket.
+ GRPC::Core::Channel.new(address, {}, :this_channel_is_insecure)
+ end
- @channel =
- if enabled?
- # NOTE: Gitaly currently runs on a Unix socket, so permissions are
- # handled using the file system and no additional authentication is
- # required (therefore the :this_channel_is_insecure flag)
- GRPC::Core::Channel.new(gitaly_address, {}, :this_channel_is_insecure)
- else
- nil
- end
+ def self.get_channel(storage)
+ if !Rails.env.production? && @channels.nil?
+ # In development mode the Rails auto-loader may reset the instance
+ # variables of this class. What we do here is not thread-safe. In normal
+ # circumstances (including production) these instance variables have
+ # been initialized from config/initializers.
+ configure_channels
+ end
+
+ @channels[storage]
+ end
+
+ def self.get_address(storage)
+ if !Rails.env.production? && @addresses.nil?
+ # In development mode the Rails auto-loader may reset the instance
+ # variables of this class. What we do here is not thread-safe. In normal
+ # circumstances (including development) these instance variables have
+ # been initialized from config/initializers.
+ configure_channels
+ end
+
+ @addresses[storage]
end
def self.enabled?
- gitaly_address.present?
+ Gitlab.config.gitaly.enabled
end
def self.feature_enabled?(feature)
@@ -39,5 +73,10 @@ module Gitlab
yield is_enabled
end
end
+
+ def self.expected_server_version
+ path = Rails.root.join(SERVER_VERSION_FILE)
+ path.read.chomp
+ end
end
end
diff --git a/lib/gitlab/gitaly_client/commit.rb b/lib/gitlab/gitaly_client/commit.rb
index 525b8d680e9..f15faebe27e 100644
--- a/lib/gitlab/gitaly_client/commit.rb
+++ b/lib/gitlab/gitaly_client/commit.rb
@@ -7,8 +7,10 @@ module Gitlab
class << self
def diff_from_parent(commit, options = {})
- stub = Gitaly::Diff::Stub.new(nil, nil, channel_override: GitalyClient.channel)
- repo = Gitaly::Repository.new(path: commit.project.repository.path_to_repo)
+ project = commit.project
+ channel = GitalyClient.get_channel(project.repository_storage)
+ stub = Gitaly::Diff::Stub.new(nil, nil, channel_override: channel)
+ repo = Gitaly::Repository.new(path: project.repository.path_to_repo)
parent = commit.parents[0]
parent_id = parent ? parent.id : EMPTY_TREE_ID
request = Gitaly::CommitDiffRequest.new(
@@ -19,6 +21,20 @@ module Gitlab
Gitlab::Git::DiffCollection.new(stub.commit_diff(request), options)
end
+
+ def is_ancestor(repository, ancestor_id, child_id)
+ project = Project.find_by_path(repository.path)
+ channel = GitalyClient.get_channel(project.repository_storage)
+ stub = Gitaly::Commit::Stub.new(nil, nil, channel_override: channel)
+ repo = Gitaly::Repository.new(path: repository.path_to_repo)
+ request = Gitaly::CommitIsAncestorRequest.new(
+ repository: repo,
+ ancestor_id: ancestor_id,
+ child_id: child_id
+ )
+
+ stub.commit_is_ancestor(request).value
+ end
end
end
end
diff --git a/lib/gitlab/gitaly_client/notifications.rb b/lib/gitlab/gitaly_client/notifications.rb
index b827a56207f..f0d93ded91b 100644
--- a/lib/gitlab/gitaly_client/notifications.rb
+++ b/lib/gitlab/gitaly_client/notifications.rb
@@ -3,14 +3,14 @@ module Gitlab
class Notifications
attr_accessor :stub
- def initialize
- @stub = Gitaly::Notifications::Stub.new(nil, nil, channel_override: GitalyClient.channel)
+ def initialize(repository_storage, relative_path)
+ @channel, @repository = Util.process_path(repository_storage, relative_path)
+ @stub = Gitaly::Notifications::Stub.new(nil, nil, channel_override: @channel)
end
- def post_receive(repo_path)
- repository = Gitaly::Repository.new(path: repo_path)
- request = Gitaly::PostReceiveRequest.new(repository: repository)
- stub.post_receive(request)
+ def post_receive
+ request = Gitaly::PostReceiveRequest.new(repository: @repository)
+ @stub.post_receive(request)
end
end
end
diff --git a/lib/gitlab/gitaly_client/ref.rb b/lib/gitlab/gitaly_client/ref.rb
new file mode 100644
index 00000000000..bfc5fa573c7
--- /dev/null
+++ b/lib/gitlab/gitaly_client/ref.rb
@@ -0,0 +1,35 @@
+module Gitlab
+ module GitalyClient
+ class Ref
+ attr_accessor :stub
+
+ def initialize(repository_storage, relative_path)
+ @channel, @repository = Util.process_path(repository_storage, relative_path)
+ @stub = Gitaly::Ref::Stub.new(nil, nil, channel_override: @channel)
+ end
+
+ def default_branch_name
+ request = Gitaly::FindDefaultBranchNameRequest.new(repository: @repository)
+ stub.find_default_branch_name(request).name.gsub(/^refs\/heads\//, '')
+ end
+
+ def branch_names
+ request = Gitaly::FindAllBranchNamesRequest.new(repository: @repository)
+ consume_refs_response(stub.find_all_branch_names(request), prefix: 'refs/heads/')
+ end
+
+ def tag_names
+ request = Gitaly::FindAllTagNamesRequest.new(repository: @repository)
+ consume_refs_response(stub.find_all_tag_names(request), prefix: 'refs/tags/')
+ end
+
+ private
+
+ def consume_refs_response(response, prefix:)
+ response.flat_map do |r|
+ r.names.map { |name| name.sub(/\A#{Regexp.escape(prefix)}/, '') }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gitaly_client/util.rb b/lib/gitlab/gitaly_client/util.rb
new file mode 100644
index 00000000000..d272c25d1f9
--- /dev/null
+++ b/lib/gitlab/gitaly_client/util.rb
@@ -0,0 +1,13 @@
+module Gitlab
+ module GitalyClient
+ module Util
+ def self.process_path(repository_storage, relative_path)
+ channel = GitalyClient.get_channel(repository_storage)
+ storage_path = Gitlab.config.repositories.storages[repository_storage]['path']
+ repository = Gitaly::Repository.new(path: File.join(storage_path, relative_path))
+
+ [channel, repository]
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/github_import/branch_formatter.rb b/lib/gitlab/github_import/branch_formatter.rb
index 5d29e698b27..8aa885fb811 100644
--- a/lib/gitlab/github_import/branch_formatter.rb
+++ b/lib/gitlab/github_import/branch_formatter.rb
@@ -11,6 +11,14 @@ module Gitlab
sha.present? && ref.present?
end
+ def user
+ raw_data.user&.login || 'unknown'
+ end
+
+ def short_sha
+ Commit.truncate_sha(sha)
+ end
+
private
def branch_exists?
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index eea4a91f17d..a8c0b47e786 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -157,7 +157,7 @@ module Gitlab
end
def restore_source_branch(pull_request)
- project.repository.fetch_ref(repo_url, "pull/#{pull_request.number}/head", pull_request.source_branch_name)
+ project.repository.create_branch(pull_request.source_branch_name, pull_request.source_branch_sha)
end
def restore_target_branch(pull_request)
diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb
index add7236e339..150afa31432 100644
--- a/lib/gitlab/github_import/pull_request_formatter.rb
+++ b/lib/gitlab/github_import/pull_request_formatter.rb
@@ -1,8 +1,8 @@
module Gitlab
module GithubImport
class PullRequestFormatter < IssuableFormatter
- delegate :exists?, :project, :ref, :repo, :sha, to: :source_branch, prefix: true
- delegate :exists?, :project, :ref, :repo, :sha, to: :target_branch, prefix: true
+ delegate :user, :project, :ref, :repo, :sha, to: :source_branch, prefix: true
+ delegate :user, :exists?, :project, :ref, :repo, :sha, :short_sha, to: :target_branch, prefix: true
def attributes
{
@@ -20,7 +20,8 @@ module Gitlab
author_id: author_id,
assignee_id: assignee_id,
created_at: raw_data.created_at,
- updated_at: raw_data.updated_at
+ updated_at: raw_data.updated_at,
+ imported: true
}
end
@@ -37,13 +38,20 @@ module Gitlab
end
def source_branch_name
- @source_branch_name ||= begin
- if cross_project?
- "pull/#{number}/#{source_branch_repo.full_name}/#{source_branch_ref}"
+ @source_branch_name ||=
+ if cross_project? || !source_branch_exists?
+ source_branch_name_prefixed
else
- source_branch_exists? ? source_branch_ref : "pull/#{number}/#{source_branch_ref}"
+ source_branch_ref
end
- end
+ end
+
+ def source_branch_name_prefixed
+ "gh-#{target_branch_short_sha}/#{number}/#{source_branch_user}/#{source_branch_ref}"
+ end
+
+ def source_branch_exists?
+ !cross_project? && source_branch.exists?
end
def target_branch
@@ -51,13 +59,17 @@ module Gitlab
end
def target_branch_name
- @target_branch_name ||= begin
- target_branch_exists? ? target_branch_ref : "pull/#{number}/#{target_branch_ref}"
- end
+ @target_branch_name ||= target_branch_exists? ? target_branch_ref : target_branch_name_prefixed
+ end
+
+ def target_branch_name_prefixed
+ "gl-#{target_branch_short_sha}/#{number}/#{target_branch_user}/#{target_branch_ref}"
end
def cross_project?
- source_branch.repo.id != target_branch.repo.id
+ return true if source_branch_repo.nil?
+
+ source_branch_repo.id != target_branch_repo.id
end
def opened?
diff --git a/lib/gitlab/import_export/hash_util.rb b/lib/gitlab/import_export/hash_util.rb
new file mode 100644
index 00000000000..d4adeeb3797
--- /dev/null
+++ b/lib/gitlab/import_export/hash_util.rb
@@ -0,0 +1,25 @@
+module Gitlab
+ module ImportExport
+ class HashUtil
+ def self.deep_symbolize_array!(array)
+ return if array.blank?
+
+ array.map! do |hash|
+ hash.deep_symbolize_keys!
+
+ yield(hash) if block_given?
+
+ hash
+ end
+ end
+
+ def self.deep_symbolize_array_with_date!(array)
+ self.deep_symbolize_array!(array) do |hash|
+ hash.select { |k, _v| k.to_s.end_with?('_date') }.each do |key, value|
+ hash[key] = Time.zone.parse(value)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_export/import_export.yml b/lib/gitlab/import_export/import_export.yml
index 25e03ec64d3..745f9a1cfbd 100644
--- a/lib/gitlab/import_export/import_export.yml
+++ b/lib/gitlab/import_export/import_export.yml
@@ -91,3 +91,5 @@ methods:
- :type
merge_request_diff:
- :utf8_st_diffs
+ merge_requests:
+ - :diff_head_sha
diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb
index 063ce74ecad..fbdd74788bc 100644
--- a/lib/gitlab/import_export/importer.rb
+++ b/lib/gitlab/import_export/importer.rb
@@ -9,7 +9,7 @@ module Gitlab
end
def execute
- if import_file && check_version! && [project_tree, avatar_restorer, repo_restorer, wiki_restorer, uploads_restorer].all?(&:restore)
+ if import_file && check_version! && [repo_restorer, wiki_restorer, project_tree, avatar_restorer, uploads_restorer].all?(&:restore)
project_tree.restored_project
else
raise Projects::ImportService::Error.new(@shared.errors.join(', '))
diff --git a/lib/gitlab/import_export/merge_request_parser.rb b/lib/gitlab/import_export/merge_request_parser.rb
new file mode 100644
index 00000000000..c20adc20bfd
--- /dev/null
+++ b/lib/gitlab/import_export/merge_request_parser.rb
@@ -0,0 +1,41 @@
+module Gitlab
+ module ImportExport
+ class MergeRequestParser
+ FORKED_PROJECT_ID = -1
+
+ def initialize(project, diff_head_sha, merge_request, relation_hash)
+ @project = project
+ @diff_head_sha = diff_head_sha
+ @merge_request = merge_request
+ @relation_hash = relation_hash
+ end
+
+ def parse!
+ if fork_merge_request? && @diff_head_sha
+ @merge_request.source_project_id = @relation_hash['project_id']
+
+ fetch_ref unless branch_exists?(@merge_request.source_branch)
+ create_target_branch unless branch_exists?(@merge_request.target_branch)
+ end
+
+ @merge_request
+ end
+
+ def create_target_branch
+ @project.repository.create_branch(@merge_request.target_branch, @merge_request.target_branch_sha)
+ end
+
+ def fetch_ref
+ @project.repository.fetch_ref(@project.repository.path, @diff_head_sha, @merge_request.source_branch)
+ end
+
+ def branch_exists?(branch_name)
+ @project.repository.branch_exists?(branch_name)
+ end
+
+ def fork_merge_request?
+ @relation_hash['source_project_id'] == FORKED_PROJECT_ID
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_export/project_tree_restorer.rb b/lib/gitlab/import_export/project_tree_restorer.rb
index cda6ddf0443..df21ff22216 100644
--- a/lib/gitlab/import_export/project_tree_restorer.rb
+++ b/lib/gitlab/import_export/project_tree_restorer.rb
@@ -119,7 +119,7 @@ module Gitlab
relation_hash: parsed_relation_hash(relation_hash),
members_mapper: members_mapper,
user: @user,
- project_id: restored_project.id)
+ project: restored_project)
end.compact
relation_hash_list.is_a?(Array) ? relation_array : relation_array.first
diff --git a/lib/gitlab/import_export/relation_factory.rb b/lib/gitlab/import_export/relation_factory.rb
index 430de9a1bf8..0545ca10862 100644
--- a/lib/gitlab/import_export/relation_factory.rb
+++ b/lib/gitlab/import_export/relation_factory.rb
@@ -30,11 +30,12 @@ module Gitlab
new(*args).create
end
- def initialize(relation_sym:, relation_hash:, members_mapper:, user:, project_id:)
+ def initialize(relation_sym:, relation_hash:, members_mapper:, user:, project:)
@relation_name = OVERRIDES[relation_sym] || relation_sym
- @relation_hash = relation_hash.except('noteable_id').merge('project_id' => project_id)
+ @relation_hash = relation_hash.except('noteable_id').merge('project_id' => project.id)
@members_mapper = members_mapper
@user = user
+ @project = project
@imported_object_retries = 0
end
@@ -67,7 +68,7 @@ module Gitlab
remove_encrypted_attributes!
@relation_hash['data'].deep_symbolize_keys! if @relation_name == :events && @relation_hash['data']
- set_st_diffs if @relation_name == :merge_request_diff
+ set_st_diff_commits if @relation_name == :merge_request_diff
end
def update_user_references
@@ -106,6 +107,8 @@ module Gitlab
imported_object do |object|
object.commit_id = nil
end
+ elsif @relation_name == :merge_requests
+ MergeRequestParser.new(@project, @relation_hash.delete('diff_head_sha'), imported_object, @relation_hash).parse!
else
imported_object
end
@@ -116,7 +119,7 @@ module Gitlab
# If source and target are the same, populate them with the new project ID.
if @relation_hash['source_project_id']
- @relation_hash['source_project_id'] = same_source_and_target? ? project_id : -1
+ @relation_hash['source_project_id'] = same_source_and_target? ? project_id : MergeRequestParser::FORKED_PROJECT_ID
end
# project_id may not be part of the export, but we always need to populate it if required.
@@ -167,6 +170,7 @@ module Gitlab
def imported_object
yield(existing_or_new_object) if block_given?
existing_or_new_object.importing = true if existing_or_new_object.respond_to?(:importing)
+
existing_or_new_object
rescue ActiveRecord::RecordNotUnique
# as the operation is not atomic, retry in the unlikely scenario an INSERT is
@@ -189,8 +193,11 @@ module Gitlab
relation_class: relation_class)
end
- def set_st_diffs
+ def set_st_diff_commits
@relation_hash['st_diffs'] = @relation_hash.delete('utf8_st_diffs')
+
+ HashUtil.deep_symbolize_array!(@relation_hash['st_diffs'])
+ HashUtil.deep_symbolize_array_with_date!(@relation_hash['st_commits'])
end
def existing_or_new_object
diff --git a/lib/gitlab/ldap/config.rb b/lib/gitlab/ldap/config.rb
index 28129198438..46deea3cc9f 100644
--- a/lib/gitlab/ldap/config.rb
+++ b/lib/gitlab/ldap/config.rb
@@ -124,9 +124,9 @@ module Gitlab
def name_proc
if allow_username_or_email_login
- Proc.new { |name| name.gsub(/@.*\z/, '') }
+ proc { |name| name.gsub(/@.*\z/, '') }
else
- Proc.new { |name| name }
+ proc { |name| name }
end
end
diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb
index fcf51b7fc5b..f98481c6d3a 100644
--- a/lib/gitlab/o_auth/user.rb
+++ b/lib/gitlab/o_auth/user.rb
@@ -147,10 +147,8 @@ module Gitlab
end
def build_new_user
- user = ::User.new(user_attributes)
- user.skip_confirmation!
- user.identities.new(extern_uid: auth_hash.uid, provider: auth_hash.provider)
- user
+ user_params = user_attributes.merge(extern_uid: auth_hash.uid, provider: auth_hash.provider, skip_confirmation: true)
+ Users::CreateService.new(nil, user_params).build
end
def user_attributes
diff --git a/lib/gitlab/polling_interval.rb b/lib/gitlab/polling_interval.rb
new file mode 100644
index 00000000000..f0c50584f07
--- /dev/null
+++ b/lib/gitlab/polling_interval.rb
@@ -0,0 +1,22 @@
+module Gitlab
+ class PollingInterval
+ include Gitlab::CurrentSettings
+
+ HEADER_NAME = 'Poll-Interval'.freeze
+
+ def self.set_header(response, interval:)
+ if polling_enabled?
+ multiplier = current_application_settings.polling_interval_multiplier
+ value = (interval * multiplier).to_i
+ else
+ value = -1
+ end
+
+ response.headers[HEADER_NAME] = value.to_s
+ end
+
+ def self.polling_enabled?
+ !current_application_settings.polling_interval_multiplier.zero?
+ end
+ end
+end
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index db325c00705..0b8959f2fb9 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -62,7 +62,7 @@ module Gitlab
data << line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
end
- OpenStruct.new(
+ FoundBlob.new(
filename: filename,
basename: basename,
ref: ref,
diff --git a/lib/gitlab/repo_path.rb b/lib/gitlab/repo_path.rb
new file mode 100644
index 00000000000..4b1d828c45c
--- /dev/null
+++ b/lib/gitlab/repo_path.rb
@@ -0,0 +1,23 @@
+module Gitlab
+ module RepoPath
+ NotFoundError = Class.new(StandardError)
+
+ def self.strip_storage_path(repo_path)
+ result = nil
+
+ Gitlab.config.repositories.storages.values.each do |params|
+ storage_path = params['path']
+ if repo_path.start_with?(storage_path)
+ result = repo_path.sub(storage_path, '')
+ break
+ end
+ end
+
+ if result.nil?
+ raise NotFoundError.new("No known storage path matches #{repo_path.inspect}")
+ end
+
+ result.sub(/\A\/*/, '')
+ end
+ end
+end
diff --git a/lib/gitlab/search_results.rb b/lib/gitlab/search_results.rb
index ccfa517e04b..efe8095beea 100644
--- a/lib/gitlab/search_results.rb
+++ b/lib/gitlab/search_results.rb
@@ -1,5 +1,26 @@
module Gitlab
class SearchResults
+ class FoundBlob
+ attr_reader :id, :filename, :basename, :ref, :startline, :data
+
+ def initialize(opts = {})
+ @id = opts.fetch(:id, nil)
+ @filename = opts.fetch(:filename, nil)
+ @basename = opts.fetch(:basename, nil)
+ @ref = opts.fetch(:ref, nil)
+ @startline = opts.fetch(:startline, nil)
+ @data = opts.fetch(:data, nil)
+ end
+
+ def path
+ filename
+ end
+
+ def no_highlighting?
+ false
+ end
+ end
+
attr_reader :current_user, :query
# Limit search results by passed projects
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index da8d8ddb8ed..36a871e5bbc 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -35,7 +35,7 @@ module Gitlab
end
def strip_key(key)
- key.split(/ /)[0, 2].join(' ')
+ key.split(/[ ]+/)[0, 2].join(' ')
end
private
@@ -88,6 +88,26 @@ module Gitlab
true
end
+ # Fetch remote for repository
+ #
+ # name - project path with namespace
+ # remote - remote name
+ # forced - should we use --force flag?
+ # no_tags - should we use --no-tags flag?
+ #
+ # Ex.
+ # fetch_remote("gitlab/gitlab-ci", "upstream")
+ #
+ def fetch_remote(storage, name, remote, forced: false, no_tags: false)
+ args = [gitlab_shell_projects_path, 'fetch-remote', storage, "#{name}.git", remote, '800']
+ args << '--force' if forced
+ args << '--no-tags' if no_tags
+
+ output, status = Popen.popen(args)
+ raise Error, output unless status.zero?
+ true
+ end
+
# Move repository
# storage - project's storage path
# path - project path with namespace
@@ -174,7 +194,10 @@ module Gitlab
# add_namespace("/path/to/storage", "gitlab")
#
def add_namespace(storage, name)
- FileUtils.mkdir_p(full_path(storage, name), mode: 0770) unless exists?(storage, name)
+ path = full_path(storage, name)
+ FileUtils.mkdir_p(path, mode: 0770) unless exists?(storage, name)
+ rescue Errno::EEXIST => e
+ Rails.logger.warn("Directory exists as a file: #{e} at: #{path}")
end
# Remove directory from repositories storage
diff --git a/lib/gitlab/testing/request_blocker_middleware.rb b/lib/gitlab/testing/request_blocker_middleware.rb
new file mode 100644
index 00000000000..aa67fa08577
--- /dev/null
+++ b/lib/gitlab/testing/request_blocker_middleware.rb
@@ -0,0 +1,61 @@
+# rubocop:disable Style/ClassVars
+
+# This is inspired by http://www.salsify.com/blog/engineering/tearing-capybara-ajax-tests
+# Rack middleware that keeps track of the number of active requests and can block new requests.
+module Gitlab
+ module Testing
+ class RequestBlockerMiddleware
+ @@num_active_requests = Concurrent::AtomicFixnum.new(0)
+ @@block_requests = Concurrent::AtomicBoolean.new(false)
+
+ # Returns the number of requests the server is currently processing.
+ def self.num_active_requests
+ @@num_active_requests.value
+ end
+
+ # Prevents the server from accepting new requests. Any new requests will return an HTTP
+ # 503 status.
+ def self.block_requests!
+ @@block_requests.value = true
+ end
+
+ # Allows the server to accept requests again.
+ def self.allow_requests!
+ @@block_requests.value = false
+ end
+
+ def initialize(app)
+ @app = app
+ end
+
+ def call(env)
+ increment_active_requests
+ if block_requests?
+ block_request(env)
+ else
+ @app.call(env)
+ end
+ ensure
+ decrement_active_requests
+ end
+
+ private
+
+ def block_requests?
+ @@block_requests.true?
+ end
+
+ def block_request(env)
+ [503, {}, []]
+ end
+
+ def increment_active_requests
+ @@num_active_requests.increment
+ end
+
+ def decrement_active_requests
+ @@num_active_requests.decrement
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/uploads_transfer.rb b/lib/gitlab/uploads_transfer.rb
index 81701831a6a..7d0c47c5361 100644
--- a/lib/gitlab/uploads_transfer.rb
+++ b/lib/gitlab/uploads_transfer.rb
@@ -1,7 +1,7 @@
module Gitlab
class UploadsTransfer < ProjectTransfer
def root_dir
- File.join(Rails.root, "public", "uploads")
+ File.join(CarrierWave.root, GitlabUploader.base_dir)
end
end
end
diff --git a/lib/gitlab/url_sanitizer.rb b/lib/gitlab/url_sanitizer.rb
index c81dc7e30d0..9ce13feb79a 100644
--- a/lib/gitlab/url_sanitizer.rb
+++ b/lib/gitlab/url_sanitizer.rb
@@ -18,6 +18,12 @@ module Gitlab
false
end
+ def self.http_credentials_for_user(user)
+ return {} unless user.respond_to?(:username)
+
+ { user: user.username }
+ end
+
def initialize(url, credentials: nil)
@url = Addressable::URI.parse(url.strip)
@credentials = credentials
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index eae1a0abf06..a8a7bf9bc12 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -1,6 +1,7 @@
require 'base64'
require 'json'
require 'securerandom'
+require 'uri'
module Gitlab
class Workhorse
@@ -15,16 +16,37 @@ module Gitlab
SECRET_LENGTH = 32
class << self
- def git_http_ok(repository, user)
+ def git_http_ok(repository, user, action)
+ repo_path = repository.path_to_repo
params = {
GL_ID: Gitlab::GlId.gl_id(user),
- RepoPath: repository.path_to_repo,
+ RepoPath: repo_path,
}
- params.merge!(
- GitalySocketPath: Gitlab.config.gitaly.socket_path,
- GitalyResourcePath: "/projects/#{repository.project.id}/git-http/info-refs",
- ) if Gitlab.config.gitaly.socket_path.present?
+ if Gitlab.config.gitaly.enabled
+ storage = repository.project.repository_storage
+ address = Gitlab::GitalyClient.get_address(storage)
+ # TODO: use GitalyClient code to assemble the Repository message
+ params[:Repository] = Gitaly::Repository.new(
+ path: repo_path,
+ storage_name: storage,
+ relative_path: Gitlab::RepoPath.strip_storage_path(repo_path),
+ ).to_h
+
+ feature_enabled = case action.to_s
+ when 'git_receive_pack'
+ # Disabled for now, see https://gitlab.com/gitlab-org/gitaly/issues/172
+ false
+ when 'git_upload_pack'
+ Gitlab::GitalyClient.feature_enabled?(:post_upload_pack)
+ when 'info_refs'
+ true
+ else
+ raise "Unsupported action: #{action}"
+ end
+
+ params[:GitalyAddress] = address if feature_enabled
+ end
params
end