Commit 587231d2 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch '5960-consider-EE-ahead-of-CE' into 'master'

Update CE branch whenever EE is ahead of CE branch

Closes #5960

See merge request gitlab-org/gitlab-ee!5719
parents f8eba60d 6953fb79
...@@ -7,8 +7,8 @@ git_version ...@@ -7,8 +7,8 @@ git_version
base = find_compare_base base = find_compare_base
current_numstat = updated_diff_numstat(base.ce_merge_base, base.ee_fetch_base) current_numstat = updated_diff_numstat(base.ce_base, base.ee_base)
updated_numstat = updated_diff_numstat(base.ce_updated_base, 'HEAD') updated_numstat = updated_diff_numstat(base.ce_head, base.ee_head)
offenses = updated_numstat.select do |file, updated_delta| offenses = updated_numstat.select do |file, updated_delta|
current_delta = current_numstat[file] current_delta = current_numstat[file]
...@@ -16,11 +16,11 @@ offenses = updated_numstat.select do |file, updated_delta| ...@@ -16,11 +16,11 @@ offenses = updated_numstat.select do |file, updated_delta|
more_lines = more_lines =
current_delta && current_delta &&
updated_delta > current_delta && updated_delta > current_delta &&
WHITELIST.all? { |pattern| !Dir.glob(pattern).include?(file) }
# Don't complain if we're just adding 1 or 2 more lines, which could be # Don't complain if we're just adding 1 or 2 more lines, which could be
# `prepend EE::Module` and a blank line that we want. # `prepend EE::Module` and a blank line that we want.
more_lines && !(current_delta == 0 && updated_delta <= 2) !(current_delta == 0 && updated_delta <= 2)
more_lines && !WHITELIST.any? { |pattern| Dir.glob(pattern).include?(file) }
end end
if offenses.empty? if offenses.empty?
......
...@@ -14,7 +14,8 @@ module EESpecificCheck ...@@ -14,7 +14,8 @@ module EESpecificCheck
'locale/gitlab.pot' 'locale/gitlab.pot'
].freeze ].freeze
CompareBase = Struct.new(:ce_merge_base, :ee_fetch_base, :ce_updated_base) CompareBase = Struct.new(:ce_base, :ee_base, :ce_head, :ee_head)
GitStatus = Struct.new(:porcelain, :head)
module_function module_function
...@@ -30,28 +31,24 @@ module EESpecificCheck ...@@ -30,28 +31,24 @@ module EESpecificCheck
git_clean git_clean
ce_fetch_head = fetch_remote_ce_branch ce_fetch_head = fetch_remote_ce_branch
ee_fetch_head = head_commit_sha
ce_fetch_base = run_git_command("merge-base canonical-ce/master #{ce_fetch_head}") ce_fetch_base = run_git_command("merge-base canonical-ce/master #{ce_fetch_head}")
ce_merge_base = run_git_command("merge-base canonical-ce/master canonical-ee/master") ce_merge_base = run_git_command("merge-base canonical-ce/master canonical-ee/master")
ee_fetch_base = run_git_command("merge-base canonical-ee/master HEAD") ee_fetch_base = run_git_command("merge-base canonical-ee/master HEAD")
ce_updated_base = ce_updated_head =
if ce_fetch_head.start_with?('canonical-ce') || # No specific CE branch find_ce_compare_head(ce_fetch_head, ce_fetch_base, ce_merge_base)
ce_fetch_base == ce_merge_base # Up-to-date, no rebase needed
ce_merge_base
else
checkout_and_rebase_ce_fetch_head_onto_ce_merge_base(
ce_fetch_head, ce_fetch_base, ce_merge_base)
end
CompareBase.new(ce_merge_base, ee_fetch_base, ce_updated_base) CompareBase.new(
ce_merge_base, ee_fetch_base, ce_updated_head, ee_fetch_head)
end end
def setup_canonical_remotes def setup_canonical_remotes
run_git_command( run_git_command(
"remote add canonical-ee https://gitlab.com/gitlab-org/gitlab-ee.git", "remote add canonical-ee https://gitlab.com/gitlab-org/gitlab-ee.git",
"remote add canonical-ce https://gitlab.com/gitlab-org/gitlab-ce.git", "remote add canonical-ce https://gitlab.com/gitlab-org/gitlab-ce.git",
"fetch canonical-ee master --quiet", "fetch canonical-ee master --quiet --depth=9999",
"fetch canonical-ce master --quiet") "fetch canonical-ce master --quiet --depth=9999")
end end
def fetch_remote_ce_branch def fetch_remote_ce_branch
...@@ -59,19 +56,63 @@ module EESpecificCheck ...@@ -59,19 +56,63 @@ module EESpecificCheck
remote_to_fetch, branch_to_fetch = find_remote_ce_branch remote_to_fetch, branch_to_fetch = find_remote_ce_branch
run_git_command("fetch #{remote_to_fetch} #{branch_to_fetch} --quiet") run_git_command("fetch #{remote_to_fetch} #{branch_to_fetch} --quiet --depth=9999")
"#{remote_to_fetch}/#{branch_to_fetch}" "#{remote_to_fetch}/#{branch_to_fetch}"
end end
def checkout_and_rebase_ce_fetch_head_onto_ce_merge_base( def find_ce_compare_head(ce_fetch_head, ce_fetch_base, ce_merge_base)
ce_fetch_head, ce_fetch_base, ce_merge_base) if git_ancestor?(ce_merge_base, ce_fetch_base)
# So that we could switch back say("CE is ahead of EE, finding backward CE head")
head = head_commit_sha find_backward_ce_head(ce_fetch_head, ce_fetch_base, ce_merge_base)
else
say("CE is behind of EE, finding forward CE head")
find_forward_ce_head(ce_merge_base, ce_fetch_head)
end
end
def git_ancestor?(ancestor, descendant)
run_git_command(
"merge-base --is-ancestor #{ancestor} #{descendant} && echo y") == 'y'
end
# Use detached HEAD so that we don't update HEAD def find_backward_ce_head(ce_fetch_head, ce_fetch_base, ce_merge_base)
run_git_command("checkout -f #{ce_fetch_head}") if ce_fetch_head.start_with?('canonical-ce') || # No specific CE branch
git_clean ce_fetch_base == ce_merge_base # Up-to-date, no rebase needed
say("CE is up-to-date, using merge-base directly")
run_git_command("merge-base #{ce_merge_base} HEAD")
else
say("Performing rebase to remove commits in CE haven't merged into EE")
checkout_and_rebase(ce_merge_base, ce_fetch_base, ce_fetch_head)
end
end
def find_forward_ce_head(ce_merge_base, ce_fetch_head)
say("Performing merge with CE master for CE branch #{ce_fetch_head}")
with_detached_head(ce_fetch_head) do
run_git_command("merge #{ce_merge_base} -s recursive -X patience -m 'ee-specific-auto-merge'")
status = git_status
if status.porcelain == ''
status.head
else
run_git_command("merge --abort")
say <<~MESSAGE
💥 Git status not clean! This means there's a conflict in
💥 #{ce_fetch_head} with canonical-ce/master. Please resolve
💥 the conflict from CE master and retry this job.
⚠️ Git status:
#{status.porcelain}
MESSAGE
exit(254)
end
end
end
# We rebase onto the commit which is the latest commit presented in both # We rebase onto the commit which is the latest commit presented in both
# CE and EE, i.e. ce_merge_base, cutting off commits aren't merged into # CE and EE, i.e. ce_merge_base, cutting off commits aren't merged into
...@@ -109,13 +150,17 @@ module EESpecificCheck ...@@ -109,13 +150,17 @@ module EESpecificCheck
# where ce_merge_base..ee_fetch_base is the update-to-date # where ce_merge_base..ee_fetch_base is the update-to-date
# CE/EE difference and ce_fetch_head..HEAD is the changes we made in # CE/EE difference and ce_fetch_head..HEAD is the changes we made in
# CE and EE branches. # CE and EE branches.
run_git_command("rebase --onto #{ce_merge_base} #{ce_fetch_base}~1 #{ce_fetch_head}") def checkout_and_rebase(new_base, old_base, target_head)
with_detached_head(target_head) do
run_git_command("rebase --onto #{new_base} #{old_base} #{target_head}")
status = git_status status = git_status
if status == '' if status.porcelain == ''
head_commit_sha status.head
else else
run_git_command("rebase --abort")
say <<~MESSAGE say <<~MESSAGE
💥 Git status not clean! This shouldn't happen, but there are two 💥 Git status not clean! This shouldn't happen, but there are two
💥 known issues. One can be worked around, and the other can't. 💥 known issues. One can be worked around, and the other can't.
...@@ -139,14 +184,24 @@ module EESpecificCheck ...@@ -139,14 +184,24 @@ module EESpecificCheck
⚠️ Git status: ⚠️ Git status:
#{status} #{status.porcelain}
MESSAGE MESSAGE
run_git_command("rebase --abort")
exit(255) exit(255)
end end
end
end
def with_detached_head(target_head)
# So that we could switch back. CI sometimes doesn't have the branch,
# so we don't use current_branch here
head = current_head
# Use detached HEAD so that we don't update HEAD
run_git_command("checkout -f #{target_head}")
git_clean
yield
ensure # ensure would still run if we call exit, don't worry ensure # ensure would still run if we call exit, don't worry
# Make sure to switch back # Make sure to switch back
run_git_command("checkout -f #{head}") run_git_command("checkout -f #{head}")
...@@ -158,7 +213,10 @@ module EESpecificCheck ...@@ -158,7 +213,10 @@ module EESpecificCheck
end end
def git_status def git_status
run_git_command("status --porcelain") GitStatus.new(
run_git_command("status --porcelain"),
head_commit_sha
)
end end
def git_clean def git_clean
...@@ -206,6 +264,10 @@ module EESpecificCheck ...@@ -206,6 +264,10 @@ module EESpecificCheck
@ce_repo_url ||= ENV.fetch('CI_REPOSITORY_URL', 'https://gitlab.com/gitlab-org/gitlab-ce.git').sub('gitlab-ee', 'gitlab-ce') @ce_repo_url ||= ENV.fetch('CI_REPOSITORY_URL', 'https://gitlab.com/gitlab-org/gitlab-ce.git').sub('gitlab-ee', 'gitlab-ce')
end end
def current_head
@current_head ||= ENV.fetch('CI_COMMIT_SHA', current_branch)
end
def current_branch def current_branch
@current_branch ||= ENV.fetch('CI_COMMIT_REF_NAME', `git rev-parse --abbrev-ref HEAD`).strip @current_branch ||= ENV.fetch('CI_COMMIT_REF_NAME', `git rev-parse --abbrev-ref HEAD`).strip
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment