summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml15
-rw-r--r--lib/gitlab/ee_compat_check.rb152
-rw-r--r--lib/tasks/gitlab/dev.rake26
3 files changed, 110 insertions, 83 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 195783454f9..34348247e91 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -213,11 +213,24 @@ rake downtime_check: *exec
rake ee_compat_check:
<<: *exec
only:
- - branches
+ - branches@gitlab-org/gitlab-ce
+ - branches@gitlab/gitlabhq
except:
- master
- tags
+ - /^[\d-]+-stable(-ee)?$/
allow_failure: yes
+ cache:
+ key: "ruby231-ee_compat_check_repo"
+ paths:
+ - ee_compat_check/repo/
+ - vendor/ruby
+ artifacts:
+ name: "${CI_BUILD_NAME}_${CI_BUILD_REF_NAME}_${CI_BUILD_REF}"
+ when: on_failure
+ expire_in: 10d
+ paths:
+ - ee_compat_check/patches/*.patch
rake db:migrate:reset:
stage: test
diff --git a/lib/gitlab/ee_compat_check.rb b/lib/gitlab/ee_compat_check.rb
index b1a6d5fe0f6..f4d1505ea91 100644
--- a/lib/gitlab/ee_compat_check.rb
+++ b/lib/gitlab/ee_compat_check.rb
@@ -2,39 +2,38 @@
module Gitlab
# Checks if a set of migrations requires downtime or not.
class EeCompatCheck
+ 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 :ce_branch, :check_dir, :ce_repo
+ attr_reader :repo_dir, :patches_dir, :ce_repo, :ce_branch
- def initialize(branch:, check_dir:, ce_repo: nil)
+ def initialize(branch:, ce_repo: CE_REPO)
+ @repo_dir = CHECK_DIR.join('repo')
+ @patches_dir = CHECK_DIR.join('patches')
@ce_branch = branch
- @check_dir = check_dir
- @ce_repo = ce_repo || 'https://gitlab.com/gitlab-org/gitlab-ce.git'
+ @ce_repo = ce_repo
end
def check
ensure_ee_repo
- delete_patches
+ ensure_patches_dir
generate_patch(ce_branch, ce_patch_full_path)
- Dir.chdir(check_dir) do
- step("In the #{check_dir} directory")
-
- step("Pulling latest master", %w[git pull --ff-only origin master])
+ Dir.chdir(repo_dir) do
+ step("In the #{repo_dir} directory")
status = catch(:halt_check) do
ce_branch_compat_check!
-
- delete_ee_branch_locally
-
+ delete_ee_branch_locally!
ee_branch_presence_check!
-
ee_branch_compat_check!
end
- delete_ee_branch_locally
- delete_patches
+ delete_ee_branch_locally!
if status.nil?
true
@@ -47,20 +46,43 @@ module Gitlab
private
def ensure_ee_repo
- if Dir.exist?(check_dir)
- step("#{check_dir} already exists")
+ if Dir.exist?(repo_dir)
+ step("#{repo_dir} already exists")
else
- cmd = %W[git clone --branch master --single-branch --depth 1 #{EE_REPO} #{check_dir}]
- step("Cloning #{EE_REPO} into #{check_dir}", cmd)
+ cmd = %W[git clone --branch master --single-branch --depth 200 #{EE_REPO} #{repo_dir}]
+ step("Cloning #{EE_REPO} into #{repo_dir}", cmd)
end
end
- def ce_branch_compat_check!
- cmd = %W[git apply --check #{ce_patch_full_path}]
- status = step("Checking if #{ce_patch_name} applies cleanly to EE/master", cmd)
+ def ensure_patches_dir
+ FileUtils.mkdir_p(patches_dir)
+ end
+
+ 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])
+
+ raise "#{branch} is too far behind master, please rebase it!" if depth >= MAX_FETCH_DEPTH
+ break if status.zero?
+ end
- if status.zero?
- puts ce_applies_cleanly_msg(ce_branch)
+ 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)
+ throw(:halt_check, :ko) unless File.exist?(patch_path)
+ end
+
+ def ce_branch_compat_check!
+ if check_patch(ce_patch_full_path).zero?
+ puts applies_cleanly_msg(ce_branch)
throw(:halt_check)
end
end
@@ -80,10 +102,8 @@ module Gitlab
step("Checking out origin/#{ee_branch}", %W[git checkout -b #{ee_branch} FETCH_HEAD])
generate_patch(ee_branch, ee_patch_full_path)
- cmd = %W[git apply --check #{ee_patch_full_path}]
- status = step("Checking if #{ee_patch_name} applies cleanly to EE/master", cmd)
- unless status.zero?
+ unless check_patch(ee_patch_full_path).zero?
puts
puts ee_branch_doesnt_apply_cleanly_msg
@@ -91,50 +111,49 @@ module Gitlab
end
puts
- puts ee_applies_cleanly_msg
+ puts applies_cleanly_msg(ee_branch)
end
- def generate_patch(branch, filepath)
- FileUtils.rm(filepath, force: true)
+ def check_patch(patch_path)
+ step("Checking out master", %w[git checkout master])
+ step("Reseting to latest master", %w[git reset --hard origin/master])
- depth = 0
- loop do
- depth += 10
- step("Fetching origin/master", %W[git fetch origin master --depth=#{depth}])
- status = step("Finding merge base with master", %W[git merge-base FETCH_HEAD #{branch}])
-
- break if status.zero? || depth > 500
- end
+ step("Checking if #{patch_path} applies cleanly to EE/master")
+ output, status = Gitlab::Popen.popen(%W[git apply --check #{patch_path}])
- raise "#{branch} is too far behind master, please rebase it!" if depth > 500
+ 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
- step("Generating the patch against master")
- output, status = Gitlab::Popen.popen(%w[git format-patch FETCH_HEAD --stdout])
- throw(:halt_check, :ko) unless status.zero?
+ if failed_files.empty?
+ status = 0
+ else
+ puts "\nConflicting files:"
+ failed_files.each do |file|
+ puts " - #{file}"
+ end
+ end
+ end
- File.write(filepath, output)
- throw(:halt_check, :ko) unless File.exist?(filepath)
+ status
end
- def delete_ee_branch_locally
+ def delete_ee_branch_locally!
command(%w[git checkout master])
step("Deleting the local #{ee_branch} branch", %W[git branch -D #{ee_branch}])
end
- def delete_patches
- step("Deleting #{ce_patch_full_path}")
- FileUtils.rm(ce_patch_full_path, force: true)
-
- step("Deleting #{ee_patch_full_path}")
- FileUtils.rm(ee_patch_full_path, force: true)
- end
-
def ce_patch_name
@ce_patch_name ||= "#{ce_branch}.patch"
end
def ce_patch_full_path
- @ce_patch_full_path ||= File.expand_path(ce_patch_name, check_dir)
+ @ce_patch_full_path ||= patches_dir.join(ce_patch_name)
end
def ee_branch
@@ -146,15 +165,18 @@ module Gitlab
end
def ee_patch_full_path
- @ee_patch_full_path ||= File.expand_path(ee_patch_name, check_dir)
+ @ee_patch_full_path ||= patches_dir.join(ee_patch_name)
end
def step(desc, cmd = nil)
puts "\n=> #{desc}\n"
if cmd
+ start = Time.now
puts "\n$ #{cmd.join(' ')}"
- command(cmd)
+ status = command(cmd)
+ puts "\nFinished in #{Time.now - start} seconds"
+ status
end
end
@@ -165,12 +187,12 @@ module Gitlab
status
end
- def ce_applies_cleanly_msg(ce_branch)
+ def applies_cleanly_msg(branch)
<<-MSG.strip_heredoc
=================================================================
🎉 Congratulations!! 🎉
- The #{ce_branch} branch applies cleanly to EE/master!
+ The #{branch} branch applies cleanly to EE/master!
Much ❤️!!
=================================================================\n
@@ -211,7 +233,7 @@ module Gitlab
# In the EE repo
$ git fetch origin
- $ git checkout -b #{ee_branch} FETCH_HEAD
+ $ 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
@@ -245,17 +267,5 @@ module Gitlab
=================================================================\n
MSG
end
-
- def ee_applies_cleanly_msg
- <<-MSG.strip_heredoc
- =================================================================
- 🎉 Congratulations!! 🎉
-
- The #{ee_branch} branch applies cleanly to EE/master!
-
- Much ❤️!!
- =================================================================\n
- MSG
- end
end
end
diff --git a/lib/tasks/gitlab/dev.rake b/lib/tasks/gitlab/dev.rake
index 5ee99dfc810..3117075b08b 100644
--- a/lib/tasks/gitlab/dev.rake
+++ b/lib/tasks/gitlab/dev.rake
@@ -1,18 +1,22 @@
namespace :gitlab do
namespace :dev do
desc 'Checks if the branch would apply cleanly to EE'
- task ee_compat_check: :environment do
- return if defined?(Gitlab::License)
- return unless ENV['CI']
+ task :ee_compat_check, [:branch] => :environment do |_, args|
+ opts =
+ if ENV['CI']
+ {
+ branch: ENV['CI_BUILD_REF_NAME'],
+ ce_repo: ENV['CI_BUILD_REPO']
+ }
+ else
+ unless args[:branch]
+ puts "Must specify a branch as an argument".color(:red)
+ exit 1
+ end
+ args
+ end
- success =
- Gitlab::EeCompatCheck.new(
- branch: ENV['CI_BUILD_REF_NAME'],
- check_dir: File.expand_path('ee-compat-check', __dir__),
- ce_repo: ENV['CI_BUILD_REPO']
- ).check
-
- if success
+ if Gitlab::EeCompatCheck.new(opts || {}).check
exit 0
else
exit 1