spec/support/shared_examples/component_updater_shared_examples.rb (144 lines of code) (raw):
# frozen_string_literal: true
RSpec.shared_examples 'component updater' do |project_class, merge_request_class, slack_notification_method|
let(:token) { 'a token' }
# Use the subject provided by the including spec
# This allows us to handle both class and module cases
describe '.new' do
context 'when GITLAB_BOT_PRODUCTION_TOKEN is not available' do
let(:token) { nil }
it 'raises error' do
ClimateControl.modify(GITLAB_BOT_PRODUCTION_TOKEN: nil) do
expect { task }.to raise_error('key not found: "GITLAB_BOT_PRODUCTION_TOKEN"')
end
end
end
end
describe '#execute' do
context 'when there are no changes' do
it 'does nothing' do
expect(task).to receive(:changed?).and_return(false)
expect(task).not_to receive(:merge_request)
expect(task).not_to receive(:ensure_source_branch_exists)
expect(task).not_to receive(:create_or_show_merge_request)
expect(ReleaseTools::Services::UpdateComponentService)
.not_to receive(:new)
expect(ReleaseTools::Services::AutoMergeService).not_to receive(:new)
without_dry_run do
task.execute
end
end
end
context 'when the merge request already exists' do
let(:merge_request) do
instance_double(
ReleaseTools::UpdateKasMergeRequest,
exists?: true,
url: 'an url',
merge_when_pipeline_succeeds?: false,
remote_issuable: build(:merge_request),
detailed_merge_status: merge_status,
notifiable?: notifiable
)
end
let(:notifiable) { true }
before do
allow(task).to receive(:merge_request).and_return(merge_request)
end
context 'when the merge request is mergeable' do
%w[mergeable unchecked not_approved].each do |merge_status|
let(:merge_status) { merge_status }
it "sets auto merge for the merge request with status #{merge_status}" do
expect(task).to receive(:changed?).and_return(true)
expect(task).to receive(:create_merge_request_and_set_auto_merge)
expect(task).not_to receive(:notify_stale_merge_request)
without_dry_run do
task.execute
end
end
end
end
context 'when the merge request is not mergeable' do
context 'when the merge request is notifiable' do
let(:merge_status) { 'ci_still_running' }
it 'sends a notification if MR is stale' do
expect(task).to receive(:changed?).and_return(true)
expect(task).not_to receive(:create_merge_request_and_set_auto_merge)
if slack_notification_method
expect(ReleaseTools::Slack::AutoDeployNotification)
.to receive(slack_notification_method)
.with(merge_request)
else
expect(task).to receive(:send_slack_notification)
end
expect(merge_request).to receive(:mark_as_stale)
without_dry_run do
task.execute
end
end
end
context 'when the merge request is not notifiable' do
let(:merge_status) { 'ci_still_running' }
let(:notifiable) { false }
it 'does not notify' do
expect(task).to receive(:changed?).and_return(true)
expect(task).not_to receive(:create_merge_request_and_set_auto_merge)
expect(task).not_to receive(:notify_stale_merge_request)
without_dry_run do
task.execute
end
end
end
end
end
context 'when the merge request does not exist' do
it 'makes sure the source branch exists, creates the merge request, updates component versions and auto-merge' do
expect(task).to receive(:changed?).and_return(true)
merge_request = instance_double(merge_request_class, exists?: false, project: double)
allow(task).to receive(:merge_request).and_return(merge_request)
expect(task).to receive(:ensure_source_branch_exists)
expect(task).to receive(:create_or_show_merge_request).with(merge_request)
update_component_service = instance_double(ReleaseTools::Services::UpdateComponentService)
expect(ReleaseTools::Services::UpdateComponentService)
.to receive(:new)
.with(project_class, task.source_branch, { skip_ci: true })
.and_return(update_component_service)
commit = instance_double(ReleaseTools::Commits)
expect(update_component_service).to receive(:execute).and_return(commit)
auto_merge_service = instance_double(ReleaseTools::Services::AutoMergeService)
expect(ReleaseTools::Services::AutoMergeService).to receive(:new).with(merge_request, { token: token, commit: commit }).and_return(auto_merge_service)
expect(auto_merge_service).to receive(:execute)
without_dry_run do
task.execute
end
end
end
end
describe '#ensure_source_branch_exist' do
it 'delegates to GitlabClient.find_or_create_branch' do
branch = instance_double(ReleaseTools::Branch)
# Use TARGET_PROJECT from the class if it's a class constant, otherwise use the project parameter
target_project = defined?(described_class::TARGET_PROJECT) ? described_class::TARGET_PROJECT : task.class::TARGET_PROJECT
expect(ReleaseTools::GitlabClient)
.to receive(:find_or_create_branch)
.with(task.source_branch, 'master', target_project)
.and_return(branch)
without_dry_run do
expect(task.ensure_source_branch_exists).to eq(branch)
end
end
end
describe '#changed?' do
it 'checks for changes in master' do
changed = double('changed?') # rubocop:disable RSpec/VerifiedDoubles
expect(ReleaseTools::Services::UpdateComponentService)
.to receive(:new)
.with(project_class, 'master')
.and_return(instance_double(ReleaseTools::Services::UpdateComponentService, changed?: changed))
expect(task.changed?).to eq(changed)
end
end
describe '#merge_request' do
it 'is a merge request from source_branch' do
expect(merge_request_class)
.to receive(:new)
.with({ source_branch: task.source_branch })
task.merge_request
end
end
end