diff --git a/qa/qa.rb b/qa/qa.rb index 106761fd215..3cc542b5c16 100644 --- a/qa/qa.rb +++ b/qa/qa.rb @@ -5,6 +5,7 @@ module QA # GitLab QA runtime classes, mostly singletons. # module Runtime + autoload :Release, 'qa/runtime/release' autoload :User, 'qa/runtime/user' autoload :Namespace, 'qa/runtime/namespace' end @@ -81,3 +82,5 @@ module QA autoload :Runner, 'qa/specs/runner' end end + +QA::Runtime::Release.autoloads diff --git a/qa/qa/runtime/release.rb b/qa/qa/runtime/release.rb new file mode 100644 index 00000000000..d64b478a41a --- /dev/null +++ b/qa/qa/runtime/release.rb @@ -0,0 +1,45 @@ +module QA + module Runtime + ## + # Class that is responsible for plugging CE/EE extensions in, depending on + # environment variable GITLAB_RELEASE that should be present in the runtime + # environment. + # + # We need that to reduce the probability of conflicts when merging + # CE to EE. + # + class Release + UnspecifiedReleaseError = Class.new(StandardError) + + def initialize(version = ENV['GITLAB_RELEASE']) + @version = version.to_s.upcase + + unless %w[CE EE].include?(@version) + raise UnspecifiedReleaseError, 'GITLAB_RELEASE env not defined!' + end + + begin + require "#{version.downcase}/strategy" + rescue LoadError + # noop + end + end + + def has_strategy? + QA.const_defined?("#{@version}::Strategy") + end + + def strategy + QA.const_get("#{@version}::Strategy") + end + + def self.method_missing(name, *args) + @release ||= self.new + + if @release.has_strategy? + @release.strategy.public_send(name, *args) + end + end + end + end +end diff --git a/qa/spec/runtime/release_spec.rb b/qa/spec/runtime/release_spec.rb new file mode 100644 index 00000000000..4995ad48ee6 --- /dev/null +++ b/qa/spec/runtime/release_spec.rb @@ -0,0 +1,62 @@ +describe QA::Runtime::Release do + context 'when release version has extension strategy' do + subject { described_class.new('CE') } + let(:strategy) { spy('CE::Strategy') } + + before do + stub_const('QA::CE::Strategy', strategy) + end + + describe '#has_strategy?' do + it 'return true' do + expect(subject.has_strategy?).to be true + end + end + + describe '#strategy' do + it 'return the strategy constant' do + expect(subject.strategy).to eq QA::CE::Strategy + end + end + + describe 'delegated class methods' do + it 'delegates all calls to strategy class' do + described_class.some_method(1, 2) + + expect(strategy).to have_received(:some_method) + .with(1, 2) + end + end + end + + context 'when release version does not have extension strategy' do + subject { described_class.new('CE') } + + describe '#has_strategy?' do + it 'returns false' do + expect(subject.has_strategy?).to be false + end + end + + describe '#strategy' do + it 'raises error' do + expect { subject.strategy }.to raise_error(NameError) + end + end + + describe 'delegated class methods' do + it 'behaves like a null object and does nothing' do + expect { described_class.some_method(2, 3) }.not_to raise_error + end + end + end + + context 'when release version is invalid or unspecified' do + describe '#new' do + it 'raises an exception' do + expect { described_class.new(nil) } + .to raise_error(described_class::UnspecifiedReleaseError) + end + end + end +end