Commit 7159693a authored by Yorick Peterse's avatar Yorick Peterse

Remove code for EE specific checks

This code is no longer needed in the single codebase setup.
parent 6259a242
# frozen_string_literal: true
# rubocop: disable Rails/Output
module Gitlab
# Checks if a set of migrations requires downtime or not.
class EeCompatCheck
CANONICAL_CE_PROJECT_URL = 'https://gitlab.com/gitlab-org/gitlab-foss'
CANONICAL_EE_REPO_URL = 'https://gitlab.com/gitlab-org/gitlab.git'
CHECK_DIR = Rails.root.join('ee_compat_check')
IGNORED_FILES_REGEX = /VERSION|CHANGELOG\.md|doc\/.+/i.freeze
PLEASE_READ_THIS_BANNER = %Q{
============================================================
===================== PLEASE READ THIS =====================
============================================================
}.freeze
STAY_STRONG_LINK_TO_DOCS = %Q{
Stay 💪! For more information, see
https://docs.gitlab.com/ce/development/automatic_ce_ee_merge.html
}.freeze
THANKS_FOR_READING_BANNER = %Q{
============================================================
==================== THANKS FOR READING ====================
============================================================\n
}.freeze
attr_reader :ee_repo_dir, :patches_dir
attr_reader :ce_project_url, :ee_repo_url
attr_reader :ce_branch, :ee_remote_with_branch, :ee_branch_found
attr_reader :job_id, :failed_files
def initialize(branch:, ce_project_url: CANONICAL_CE_PROJECT_URL, job_id: nil)
@ee_repo_dir = CHECK_DIR.join('ee-repo')
@patches_dir = CHECK_DIR.join('patches')
@ce_branch = branch
@ce_project_url = ce_project_url
@ee_repo_url = ce_public_repo_url.sub('gitlab-ce', 'gitlab-ee')
@job_id = job_id
end
def check
ensure_patches_dir
# We're generating the patch against the canonical-ce remote since forks'
# master branch are not necessarily up-to-date.
add_remote('canonical-ce', "#{CANONICAL_CE_PROJECT_URL}.git")
generate_patch(branch: ce_branch, patch_path: ce_patch_full_path, branch_remote: 'origin', master_remote: 'canonical-ce')
ensure_ee_repo
Dir.chdir(ee_repo_dir) do
step("In the #{ee_repo_dir} directory")
ee_remotes.each do |key, url|
add_remote(key, url)
end
fetch(branch: 'master', depth: 20, remote: 'canonical-ee')
status = catch(:halt_check) do
ce_branch_compat_check!
delete_ee_branches_locally!
ee_branch_presence_check!
step("Checking out #{ee_remote_with_branch}/#{ee_branch_found}", %W[git checkout -b #{ee_branch_found} #{ee_remote_with_branch}/#{ee_branch_found}])
generate_patch(branch: ee_branch_found, patch_path: ee_patch_full_path, branch_remote: ee_remote_with_branch, master_remote: 'canonical-ee')
ee_branch_compat_check!
end
delete_ee_branches_locally!
status.nil?
end
end
private
def fork?
ce_project_url != CANONICAL_CE_PROJECT_URL
end
def ee_remotes
return @ee_remotes if defined?(@ee_remotes)
remotes =
{
'ee' => ee_repo_url,
'canonical-ee' => CANONICAL_EE_REPO_URL
}
remotes.delete('ee') unless fork?
@ee_remotes = remotes
end
def add_remote(name, url)
step(
"Adding the #{name} remote (#{url})",
%W[git remote add #{name} #{url}]
)
end
def ensure_ee_repo
unless clone_repo(ee_repo_url, ee_repo_dir)
# Fallback to using the canonical EE if there is no forked EE
clone_repo(CANONICAL_EE_REPO_URL, ee_repo_dir)
end
end
def clone_repo(url, dir)
_, status = step(
"Cloning #{url} into #{dir}",
%W[git clone --branch master --single-branch --depth=200 #{url} #{dir}]
)
status.zero?
end
def ensure_patches_dir
FileUtils.mkdir_p(patches_dir)
end
def generate_patch(branch:, patch_path:, branch_remote:, master_remote:)
FileUtils.rm(patch_path, force: true)
find_merge_base_with_master(branch: branch, branch_remote: branch_remote, master_remote: master_remote)
step(
"Generating the patch against #{master_remote}/master in #{patch_path}",
%W[git diff --binary #{master_remote}/master...#{branch_remote}/#{branch}]
) do |output, status|
throw(:halt_check, :ko) unless status.zero?
File.write(patch_path, output)
throw(:halt_check, :ko) unless File.exist?(patch_path)
end
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
def ee_branch_presence_check!
ee_remotes.keys.each do |remote|
output, _ = step(
"Searching #{remote}",
%W[git ls-remote #{remote} *#{minimal_ee_branch_name}*])
branches =
output.scan(%r{(?<=refs/heads/|refs/tags/).+}).sort_by(&:size)
next if branches.empty?
branch = branches.first
step("Fetching #{remote}/#{branch}", %W[git fetch #{remote} #{branch}])
@ee_remote_with_branch = remote
@ee_branch_found = branch
return true
end
puts
puts ce_branch_doesnt_apply_cleanly_and_no_ee_branch_msg
throw(:halt_check, :ko)
end
def ee_branch_compat_check!
unless check_patch(ee_patch_full_path).zero?
puts
puts ee_branch_doesnt_apply_cleanly_msg
throw(:halt_check, :ko)
end
puts
puts applies_cleanly_msg(ee_branch_found)
end
def check_patch(patch_path)
step("Checking out master", %w[git checkout master])
step("Resetting to latest master", %w[git reset --hard canonical-ee/master])
step(
"Checking if #{patch_path} applies cleanly to EE/master",
# Don't use --check here because it can result in a 0-exit status even
# though the patch doesn't apply cleanly, e.g.:
# > git apply --check --3way foo.patch
# error: patch failed: lib/gitlab/ee_compat_check.rb:74
# Falling back to three-way merge...
# Applied patch to 'lib/gitlab/ee_compat_check.rb' with conflicts.
# > echo $?
# 0
%W[git apply --3way #{patch_path}]
) do |output, status|
puts output
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
status = 0 if failed_files.empty?
end
command(%w[git reset --hard])
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?(branch:, branch_remote:, master_remote:)
step(
"Finding merge base with #{master_remote}/master",
%W[git merge-base #{master_remote}/master #{branch_remote}/#{branch}]
) do |output, status|
if status.zero?
puts "Merge base was found: #{output}"
true
end
end
end
def find_merge_base_with_master(branch:, branch_remote:, master_remote:)
# 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, remote: branch_remote)
fetch(branch: 'master', depth: depth, remote: master_remote)
merge_base_found?(branch: branch, branch_remote: branch_remote, master_remote: master_remote)
end
raise "\n#{branch} is too far behind #{master_remote}/master, please rebase it!\n" unless success
end
def fetch(branch:, depth:, remote: 'origin')
step(
"Fetching deeper...",
%W[git fetch --depth=#{depth} --prune #{remote} +refs/heads/#{branch}:refs/remotes/#{remote}/#{branch}]
) do |output, status|
raise "Fetch failed: #{output}" unless status.zero?
end
end
def ce_patch_name
@ce_patch_name ||= patch_name_from_branch(ce_branch)
end
def ce_patch_full_path
@ce_patch_full_path ||= patches_dir.join(ce_patch_name)
end
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_found)
end
def ee_patch_full_path
@ee_patch_full_path ||= patches_dir.join(ee_patch_name)
end
def minimal_ee_branch_name
@minimal_ee_branch_name ||= ce_branch.sub(/(\Ace\-|\-ce\z)/, '')
end
def patch_name_from_branch(branch_name)
"#{branch_name.parameterize}.patch"
end
def patch_url
"#{ce_project_url}/-/jobs/#{job_id}/artifacts/raw/ee_compat_check/patches/#{ce_patch_name}"
end
def step(desc, cmd = nil)
puts "\n=> #{desc}\n"
if cmd
start = Time.now
puts "\n$ #{cmd.join(' ')}"
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)
Gitlab::Popen.popen(cmd)
end
# We're "re-creating" the repo URL because ENV['CI_REPOSITORY_URL'] contains
# redacted credentials (e.g. "***:****") which are useless in instructions
# the job gives.
def ce_public_repo_url
"#{ce_project_url}.git"
end
def applies_cleanly_msg(branch)
%Q{
#{PLEASE_READ_THIS_BANNER}
🎉 Congratulations!! 🎉
The `#{branch}` branch applies cleanly to EE/master!
Much ❤️! For more information, see
https://docs.gitlab.com/ce/development/automatic_ce_ee_merge.html
#{THANKS_FOR_READING_BANNER}
}
end
def ce_branch_doesnt_apply_cleanly_and_no_ee_branch_msg
ee_repos = ee_remotes.values.uniq
%Q{
#{PLEASE_READ_THIS_BANNER}
💥 Oh no! 💥
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 #{ee_repos.join(' nor in ')}.
If you're a community contributor, don't worry, someone from
GitLab Inc. will take care of this, and you don't have to do anything.
If you're willing to help, and are ok to contribute to EE as well,
you're welcome to help. You could follow the instructions below.
#{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 judgement!
There are different ways to create such branch:
1. Create a new branch from master and cherry-pick your CE commits
# In the EE repo
$ git fetch #{CANONICAL_EE_REPO_URL} master
$ git checkout -b #{ee_branch_prefix} FETCH_HEAD
$ git fetch #{ce_public_repo_url} #{ce_branch}
$ git cherry-pick SHA # Repeat for all the commits you want to pick
Note: You can squash the `#{ce_branch}` commits into a single "Port of #{ce_branch} to EE" commit.
2. Apply your branch's patch to EE
# In the EE repo
$ git fetch #{CANONICAL_EE_REPO_URL} master
$ git checkout -b #{ee_branch_prefix} FETCH_HEAD
$ wget #{patch_url} && git apply --3way #{ce_patch_name}
At this point you might have conflicts such as:
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
Resolve them, stage the changes and commit them.
If the patch couldn't be applied cleanly, use the following command:
# In the EE repo
$ git apply --reject #{ce_patch_name}
This option makes git apply the parts of the patch that are applicable,
and leave the rejected hunks in corresponding `.rej` files.
You can then resolve the conflicts highlighted in `.rej` by
manually applying the correct diff from the `.rej` file to the file with conflicts.
When finished, you can delete the `.rej` files and commit your changes.
⚠️ Don't forget to push your branch to gitlab-ee:
# In the EE repo
$ git push origin #{ee_branch_prefix}
⚠️ Also, don't forget to create a new merge request on gitlab-ee and
cross-link it with the CE merge request.
Once this is done, you can retry this failed job, and it should pass.
#{STAY_STRONG_LINK_TO_DOCS}
#{THANKS_FOR_READING_BANNER}
}
end
def ee_branch_doesnt_apply_cleanly_msg
%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_found}` branch
exists in #{ee_repo_url}, it does not apply cleanly either to
EE/master!
#{conflicting_files_msg}
Please update the `#{ee_branch_found}`, push it again to gitlab-ee, and
retry this job.
#{STAY_STRONG_LINK_TO_DOCS}
#{THANKS_FOR_READING_BANNER}
}
end
def conflicting_files_msg
header = "The conflicts detected were as follows:\n"
separator = "\n - "
failed_items = failed_files.join(separator)
"#{header}#{separator}#{failed_items}"
end
end
end
desc 'Checks if the branch would apply cleanly to EE'
task ee_compat_check: :environment do
Rake::Task['gitlab:dev:ee_compat_check'].invoke
end
namespace :gitlab do
namespace :dev do
desc 'Checks if the branch would apply cleanly to EE'
task :ee_compat_check, [:branch] => :environment do |_, args|
opts =
if ENV['CI']
{
ce_project_url: ENV['CI_PROJECT_URL'],
branch: ENV['CI_COMMIT_REF_NAME'],
job_id: ENV['CI_JOB_ID']
}
else
unless args[:branch]
puts "Must specify a branch as an argument".color(:red)
exit 1
end
args
end
if File.basename(Rails.root) == 'gitlab'
puts "Skipping EE projects"
exit 0
elsif Gitlab::EeCompatCheck.new(opts || {}).check
exit 0
else
exit 1
end
end
end
end
# frozen_string_literal: true
# rubocop: disable CodeReuse/ActiveRecord
module EESpecificCheck
WHITELIST = [
'CHANGELOG-EE.md',
'scripts/**/*',
'vendor/assets/javascripts/jasmine-jquery.js',
'.gitlab-ci.yml',
'.gitlab/ci/rails.gitlab-ci.yml',
'db/schema.rb',
'locale/gitlab.pot'
].freeze
CompareBase = Struct.new(:ce_base, :ee_base, :ce_head, :ee_head)
GitStatus = Struct.new(:porcelain, :head)
module_function
def git_version
say run_git_command('--version')
end
def say(message)
warn "\n#{message}", "\n" # puts would eat trailing newline
end
def find_compare_base
git_clean
ce_fetch_head = fetch_remote_ce_branch
ee_fetch_head = head_commit_sha
ce_fetch_base = find_merge_base('canonical-ce/master', ce_fetch_head)
ee_fetch_base = find_merge_base('canonical-ee/master', 'HEAD')
ce_merge_base = find_merge_base(ce_fetch_head, ee_fetch_head)
ce_updated_head =
find_ce_compare_head(ce_fetch_head, ce_fetch_base, ce_merge_base)
CompareBase.new(
ce_merge_base, ee_fetch_base, ce_updated_head, ee_fetch_head)
end
def setup_canonical_remotes
run_git_command(
"remote add canonical-ee https://gitlab.com/gitlab-org/gitlab.git",
"remote add canonical-ce https://gitlab.com/gitlab-org/gitlab-foss.git",
"fetch canonical-ee master --quiet --depth=9999",
"fetch canonical-ce master --quiet --depth=9999")
end
def fetch_remote_ce_branch
setup_canonical_remotes
remote_to_fetch, branch_to_fetch = find_remote_ce_branch
run_git_command("fetch #{remote_to_fetch} #{branch_to_fetch} --quiet --depth=9999")
"#{remote_to_fetch}/#{branch_to_fetch}"
end
def find_merge_base(left, right)
merge_base = run_git_command("merge-base #{left} #{right}")
return merge_base unless merge_base.empty?
say <<~MESSAGE
💥 Unfortunately we cannot find the merge-base for #{left} and #{right},
💥 and we'll try to fix that in:
https://gitlab.com/gitlab-org/gitlab/issues/9120
💥 Before that, please run this job locally as a workaround:
./scripts/ee-specific-lines-check
💥 And paste the result as a discussion to show it to the maintainer.
💥 If you have any questions, please ping @godfat to investigate and
💥 clarify.
MESSAGE
exit(253)
end
def find_ce_compare_head(ce_fetch_head, ce_fetch_base, ce_merge_base)
if git_ancestor?(ce_merge_base, ce_fetch_base)
say("CE is ahead of EE, finding backward CE head")
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
def find_backward_ce_head(ce_fetch_head, ce_fetch_base, ce_merge_base)
if ce_fetch_head.start_with?('canonical-ce') # No specific CE branch
say("No CE branch found, using merge base directly")
ce_merge_base
elsif ce_fetch_base == ce_merge_base # Up-to-date, no rebase needed
say("EE is up-to-date with CE, using #{ce_fetch_head} directly")
ce_fetch_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
diff = run_git_command("diff")
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 diff:
#{diff}
MESSAGE
exit(254)
end
end
end
# 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
# EE yet. Here's an example:
#
# * o: Relevant commits
# * x: Irrelevant commits
# * !: Commits we want to cut off from CE branch
#
# ^-> o CE branch (ce_fetch_head)
# / (ce_fetch_base)
# o -> o -> ! -> x CE master
# v (ce_merge_base)
# o -> o -> o -> x EE master
# \ (ee_fetch_base)
# v-> o EE branch
#
# We want to rebase above into this: (we only change the connection)
#
# -> - -> o CE branch (ce_fetch_head)
# / (ce_fetch_base)
# o -> o -> ! -> x CE master
# v (ce_merge_base)
# o -> o -> o -> x EE master
# \ (ee_fetch_base)
# v-> o EE branch
#
# Therefore we rebase onto ce_merge_base, which is based off CE master,
# for the CE branch (ce_fetch_head), effective remove the commit marked
# as ! in the graph for CE branch. We need to remove it because it's not
# merged into EE yet, therefore won't be available in the EE branch.
#
# After rebase is done, then we could compare against
# ce_merge_base..ee_fetch_base along with ce_fetch_head..HEAD (EE branch)
# 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 and EE branches.
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
if status.porcelain == ''
status.head
else
diff = run_git_command("diff")
run_git_command("rebase --abort")
say <<~MESSAGE
💥 Git status is not clean! This means the CE branch has or had a
💥 conflict with CE master, and we cannot resolve this in an
💥 automatic way.
💥
💥 Please rebase #{target_head} with CE master.
💥
💥 For more details, please read:
💥 https://gitlab.com/gitlab-org/gitlab/issues/6038#note_86862115
💥
💥 Git diff:
#{diff}
MESSAGE
exit(255)
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
# Make sure to switch back
run_git_command("checkout -f #{head}")
git_clean
end
def head_commit_sha
run_git_command("rev-parse HEAD")
end
def git_status
GitStatus.new(
run_git_command("status --porcelain"),
head_commit_sha
)
end
def git_clean
# We're still seeing errors not ignoring knapsack/ and rspec_flaky/
# Instead of waiting that populate over all the branches, we could
# just remove untracked files anyway, only on CI of course in case
# we're wiping people's data!
# See https://gitlab.com/gitlab-org/gitlab/issues/5912
# Also see https://gitlab.com/gitlab-org/gitlab/-/jobs/68194333
run_git_command('clean -fd') if ENV['CI']
end
def remove_remotes
run_git_command(
"remote remove canonical-ee",
"remote remove canonical-ce",
"remote remove target-ce")
end
def updated_diff_numstat(from, to)
scan_diff_numstat(
run_git_command("diff #{from}..#{to} --numstat -- . ':!ee' ':!qa/qa/ee' ':!qa/qa/ee.rb' ':!qa/qa/specs/features/ee'"))
end
def find_remote_ce_branch
branch_to_fetch = matching_ce_refs.first
if branch_to_fetch
say "💪 We found the branch '#{branch_to_fetch}' in the #{ce_repo_url} repository. We will fetch it."
run_git_command("remote add target-ce #{ce_repo_url}")
['target-ce', branch_to_fetch]
else
say <<~MESSAGE
⚠️ We did not find a branch that would match the current '#{current_branch}' branch in the #{ce_repo_url} repository. We will fetch 'master' instead.
ℹ️ If you have a CE branch for the current branch, make sure that its name includes '#{minimal_ce_branch_name}'.
MESSAGE
%w[canonical-ce master]
end
end
def ce_repo_url
@ce_repo_url ||=
begin
repo_url = ENV.fetch('CI_REPOSITORY_URL', 'https://gitlab.com/gitlab-org/gitlab-foss.git')
# This workaround can be removed once we rename the dev CE project
# https://gitlab.com/gitlab-org/gitlab-foss/issues/59107
project_name = repo_url =~ /dev\.gitlab\.org/ ? 'gitlabhq' : 'gitlab-ce'
repo_url.sub('gitlab-ee', project_name)
end
end
def current_head
@current_head ||= ENV.fetch('CI_COMMIT_SHA', current_branch)
end
def current_branch
@current_branch ||= ENV.fetch('CI_COMMIT_REF_NAME', `git rev-parse --abbrev-ref HEAD`).strip
end
def minimal_ce_branch_name
@minimal_ce_branch_name ||= current_branch.sub(/(\Aee\-|\-ee\z)/, '')
end
def matching_ce_refs
@matching_ce_refs ||=
run_git_command("ls-remote #{ce_repo_url} \"*#{minimal_ce_branch_name}*\"")
.scan(%r{(?<=refs/heads/|refs/tags/).+})
.select { |branch| branch.match?(/\b#{minimal_ce_branch_name}\b/i) }
.sort_by(&:size)
end
def scan_diff_numstat(numstat)
numstat.scan(/(\d+)\s+(\d+)\s+(.+)/)
.each_with_object(Hash.new(0)) do |(added, deleted, file), result|
result[file] = added.to_i + deleted.to_i
end
end
def run_git_command(*commands)
cmds = commands.map { |cmd| "git #{cmd}" }
output = run_command(*cmds)
if commands.size == 1
output.first
else
output
end
end
def run_command(*commands)
commands.map do |cmd|
warn "=> Running `#{cmd}`"
`#{cmd}`.strip
end
end
end
if $0 == __FILE__
require 'rspec/autorun'
RSpec.describe EESpecificCheck do
subject { Class.new { include EESpecificCheck }.new }
before do
allow(subject).to receive(:warn)
EESpecificCheck.private_instance_methods.each do |name|
subject.class.__send__(:public, name) # rubocop:disable GitlabSecurity/PublicSend
end
end
describe '.run_git_command' do
it 'returns the single output when there is a single command' do
output = subject.run_git_command('status')
expect(output).to be_kind_of(String)
expect(subject).to have_received(:warn).with(/git status/)
end
it 'returns an array of output for more commands' do
output = subject.run_git_command('status', 'help')
expect(output).to all(be_a(String))
expect(subject).to have_received(:warn).with(/git status/)
expect(subject).to have_received(:warn).with(/git help/)
end
end
describe '.find_merge_base' do
context 'when it cannot find the merge base' do
before do
allow(subject).to receive(:say)
allow(subject).to receive(:exit)
expect(subject).to receive(:run_git_command).and_return('')
end
it 'calls exit(253) to fail the job and ask run it locally' do
subject.find_merge_base('master', 'HEAD')
expect(subject).to have_received(:say)
.with(Regexp.union('./scripts/ee-specific-lines-check'))
expect(subject).to have_received(:exit)
.with(253)
end
end
context 'when it found the merge base' do
before do
expect(subject).to receive(:run_git_command).and_return('deadbeef')
end
it 'returns the found merge base' do
output = subject.find_merge_base('master', 'HEAD')
expect(output).to eq('deadbeef')
end
end
end
describe '.matching_ce_refs' do
before do
expect(subject).to receive(:current_branch).and_return(ee_branch)
expect(subject).to receive(:run_git_command)
.and_return(ls_remote_output)
end
describe 'simple cases' do
let(:ls_remote_output) do
<<~OUTPUT
d6602ec5194c87b0fc87103ca4d67251c76f233a\trefs/tags/v9
f25a265a342aed6041ab0cc484224d9ca54b6f41\trefs/tags/v9.12
c5db5456ae3b0873fc659c19fafdde22313cc441\trefs/tags/v9.123
0918385dbd9656cab0d1d81ba7453d49bbc16250\trefs/heads/v9.x
28862662b749fe981386814e2dba87b0e72c1eab\trefs/remotes/remote_mirror_3059/v9-to-fix-http-case-problems
5e3496802098c86050c5b463507f3a68a83a9f02\trefs/remotes/remote_mirror_3059/29036-use-slack-service-v9
OUTPUT
end
context 'with a ee- prefix' do
let(:ee_branch) { 'ee-v9' }
it 'sorts by matching size' do
expect(subject.matching_ce_refs).to eq(%w[v9 v9.x v9.12 v9.123])
end
end
context 'with a -ee suffix' do
let(:ee_branch) { 'v9-ee' }
it 'sorts by matching size' do
expect(subject.matching_ce_refs).to eq(%w[v9 v9.x v9.12 v9.123])
end
end
end
describe 'with ambiguous branch name' do
let(:ls_remote_output) do
<<~OUTPUT
954d7119384c9f2a3c862bac97beb641eb8755d6\trefs/heads/feature/sm/35954-expand-kubernetesservice-to-use-username-password
954d7119384c9f2a3c862bac97beb641eb8755d6\trefs/heads/ce-to-ee-231
954d7119384c9f2a3c862bac97beb641eb8755d6\trefs/heads/ce-to-ee-2
954d7119384c9f2a3c862bac97beb641eb8755d6\trefs/heads/ce-to-1
954d7119384c9f2a3c862bac97beb641eb8755d6\trefs/heads/ee-to-ce-123
954d7119384c9f2a3c862bac97beb641eb8755d6\trefs/heads/ee-to-ce-12
954d7119384c9f2a3c862bac97beb641eb8755d6\trefs/heads/to-ce-1
28862662b749fe981386814e2dba87b0e72c1eab\trefs/remotes/remote_mirror_3059/27056-upgrade-vue-resource-to-1-0-3-to-fix-http-case-problems
5e3496802098c86050c5b463507f3a68a83a9f02\trefs/remotes/remote_mirror_3059/29036-use-slack-service-to-notify-of-failed-pipelines
OUTPUT
end
context 'with a ee- prefix' do
let(:ee_branch) { 'ee-to-ce' }
let(:minimal_ce_branch) { 'to-ce' }
it 'sorts by matching size' do
expect(subject.matching_ce_refs).to eq(%w[to-ce-1 ee-to-ce-12 ee-to-ce-123])
end
end
context 'with a -ee suffix' do
let(:ee_branch) { 'ce-to-ee' }
let(:minimal_ce_branch) { 'ce-to' }
it 'sorts by matching size' do
expect(subject.matching_ce_refs).to eq(%w[ce-to-1 ce-to-ee-2 ce-to-ee-231])
end
end
end
end
end
end
......@@ -37,10 +37,6 @@ tasks = [
%w[scripts/lint-rugged]
]
if Gitlab.ee?
tasks.unshift(%w[ruby -rbundler/setup scripts/ee_specific_check/ee_specific_check.rb])
end
static_analysis = Gitlab::Popen::Runner.new
static_analysis.run(tasks) do |cmd, &run|
......
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