diff --git a/lib/travis/remote_vcs/organization.rb b/lib/travis/remote_vcs/organization.rb index 3099608a5..7a11522c9 100644 --- a/lib/travis/remote_vcs/organization.rb +++ b/lib/travis/remote_vcs/organization.rb @@ -13,6 +13,15 @@ def destroy(org_id:) Travis.logger.error("Failed to destroy organization: #{e.message}") false end + + def restore(org_id:) + request(:post, __method__, false) do |req| + req.url "organizations/#{org_id}/restore" + end + rescue ResponseError => e + Travis.logger.error("Failed to restore organization: #{e.message}") + false + end end end end diff --git a/lib/travis/remote_vcs/repository.rb b/lib/travis/remote_vcs/repository.rb index b62c9b868..3d9d41a60 100644 --- a/lib/travis/remote_vcs/repository.rb +++ b/lib/travis/remote_vcs/repository.rb @@ -74,14 +74,24 @@ def set_perforce_ticket(repository_id:, user_id:) {} end - def destroy(repository_id:) + def destroy(repository_id:, vcs_type:) request(:delete, __method__, false) do |req| req.url "repos/#{repository_id}" + req.params['vcs_type'] = vcs_type end rescue ResponseError => e Travis.logger.error("Failed to destroy repository: #{e.message}") false end + + def restore(repository_id:) + request(:post, __method__, false) do |req| + req.url "repos/#{repository_id}/restore" + end + rescue ResponseError => e + Travis.logger.error("Failed to restore repository: #{e.message}") + false + end end end end diff --git a/lib/travis/services/assembla_notify_service.rb b/lib/travis/services/assembla_notify_service.rb index e0811c9d5..58029069c 100644 --- a/lib/travis/services/assembla_notify_service.rb +++ b/lib/travis/services/assembla_notify_service.rb @@ -6,24 +6,25 @@ module Travis module Services class AssemblaNotifyService - VALID_ACTIONS = %w[destroy].freeze + VALID_ACTIONS = %w[restrict restore].freeze VALID_OBJECTS = %w[space tool].freeze def initialize(payload) - @action = payload[:action] - @object = payload[:object] - @object_id = payload[:id] + @action = payload['action'] + @object = payload['object'] + @object_id = payload['id'] end def run - validate + return false unless validate + case @object when 'tool' - handle_tool_destruction + handle_tool_action when 'space' - handle_space_destruction + handle_space_action else - { status: 400, body: { error: 'Unsupported object type for destruction' } } + false end end @@ -31,22 +32,36 @@ def run def validate unless VALID_ACTIONS.include?(@action) - return { status: 400, body: { error: 'Invalid action', allowed_actions: VALID_ACTIONS } } + Travis.logger.error("Invalid action: #{@action}. Allowed actions: #{VALID_ACTIONS.join(', ')}") + return false end unless VALID_OBJECTS.include?(@object) - return { status: 400, body: { error: 'Invalid object type', allowed_objects: VALID_OBJECTS } } + Travis.logger.error("Invalid object type: #{@object}. Allowed objects: #{VALID_OBJECTS.join(', ')}") + return false end + + true end - def handle_tool_destruction + def handle_tool_action vcs_repository = Travis::RemoteVCS::Repository.new - vcs_repository.destroy(repository_id: @object_id) + case @action + when 'restrict' + vcs_repository.destroy(repository_id: @object_id, vcs_type: 'AssemblaRepository') + when 'restore' + vcs_repository.restore(repository_id: @object_id) + end end - def handle_space_destruction + def handle_space_action vcs_organization = Travis::RemoteVCS::Organization.new - vcs_organization.destroy(org_id: @object_id) + case @action + when 'restrict' + vcs_organization.destroy(org_id: @object_id) + when 'restore' + vcs_organization.restore(org_id: @object_id) + end end end end diff --git a/spec/lib/services/assembla_notify_service_spec.rb b/spec/lib/services/assembla_notify_service_spec.rb index ba0ed3d33..2b730d691 100644 --- a/spec/lib/services/assembla_notify_service_spec.rb +++ b/spec/lib/services/assembla_notify_service_spec.rb @@ -2,71 +2,86 @@ require 'travis/services/assembla_notify_service' RSpec.describe Travis::Services::AssemblaNotifyService do - let(:payload) { { action: 'destroy', object: 'tool', id: '12345' } } + let(:payload) { { 'action' => 'restrict', 'object' => 'tool', 'id' => '12345' } } let(:service) { described_class.new(payload) } let(:vcs_repository) { instance_double(Travis::RemoteVCS::Repository) } let(:vcs_organization) { instance_double(Travis::RemoteVCS::Organization) } before do allow(Travis::RemoteVCS::Repository).to receive(:new).and_return(vcs_repository) - allow(vcs_repository).to receive(:destroy) + allow(vcs_repository).to receive(:destroy).with(any_args) + allow(vcs_repository).to receive(:restore) allow(Travis::RemoteVCS::Organization).to receive(:new).and_return(vcs_organization) allow(vcs_organization).to receive(:destroy) + allow(vcs_organization).to receive(:restore) allow(Travis.logger).to receive(:error) end describe '#run' do - context 'with a valid payload for tool destruction' do - it 'calls handle_tool_destruction' do - expect(service).to receive(:handle_tool_destruction) + context 'with a valid payload for tool restriction' do + it 'calls destroy on the vcs_repository' do + expect(vcs_repository).to receive(:destroy).with(repository_id: '12345', vcs_type: 'AssemblaRepository') service.run end end - context 'with a valid payload for space destruction' do - let(:payload) { { action: 'destroy', object: 'space', id: '67890' } } - - it 'calls handle_space_destruction' do - expect(service).to receive(:handle_space_destruction) + context 'with a valid payload for tool restoration' do + let(:payload) { { 'action' => 'restore', 'object' => 'tool', 'id' => '12345' } } + it 'calls restore on the vcs_repository' do + expect(vcs_repository).to receive(:restore).with(repository_id: '12345') service.run end end - context 'with an invalid object type' do - let(:payload) { { action: 'destroy', object: 'repository', id: '12345' } } + context 'with a valid payload for space restriction' do + let(:payload) { { 'action' => 'restrict', 'object' => 'space', 'id' => '67890' } } - it 'returns an error' do - result = service.run - expect(result[:status]).to eq(400) + it 'calls destroy on the vcs_organization' do + expect(vcs_organization).to receive(:destroy).with(org_id: '67890') + service.run end end - context 'with an unsupported object type for destruction' do - before do - stub_const("Travis::Services::AssemblaNotifyService::VALID_OBJECTS", %w[space tool unsupported]) + context 'with a valid payload for space restoration' do + let(:payload) { { 'action' => 'restore', 'object' => 'space', 'id' => '67890' } } + + it 'calls restore on the vcs_organization' do + expect(vcs_organization).to receive(:restore).with(org_id: '67890') + service.run end - let(:payload) { { action: 'destroy', object: 'unsupported', id: '12345' } } + end + + context 'with an invalid object type' do + let(:payload) { { 'action' => 'restrict', 'object' => 'repository', 'id' => '12345' } } - it 'returns an error' do - result = service.run - expect(result[:status]).to eq(400) + it 'returns false and logs an error' do + expect(service.run).to be_falsey + expect(Travis.logger).to have_received(:error).with("Invalid object type: repository. Allowed objects: space, tool") end end - end - describe '#handle_tool_destruction' do - it 'destroys the repository using RemoteVCS' do - expect(vcs_repository).to receive(:destroy).with(repository_id: '12345') - service.send(:handle_tool_destruction) + context 'with an invalid action type' do + let(:payload) { { 'action' => 'modify', 'object' => 'tool', 'id' => '12345' } } + + it 'returns false and logs an error' do + expect(service.run).to be_falsey + expect(Travis.logger).to have_received(:error).with("Invalid action: modify. Allowed actions: restrict, restore") + end end - end - describe '#handle_space_destruction' do - let(:payload) { { action: 'destroy', object: 'space', id: '67890' } } + context 'with an unsupported object type for an action' do + before do + stub_const("Travis::Services::AssemblaNotifyService::VALID_OBJECTS", %w[space tool unsupported]) + end + let(:payload) { { 'action' => 'restrict', 'object' => 'unsupported', 'id' => '12345' } } - it 'destroys the organization using RemoteVCS' do - expect(vcs_organization).to receive(:destroy).with(org_id: '67890') - service.send(:handle_space_destruction) + it 'returns false without logging an error for the action' do + expect(service.run).to be_falsey + expect(vcs_repository).not_to receive(:destroy) + expect(vcs_repository).not_to receive(:restore) + expect(vcs_organization).not_to receive(:destroy) + expect(vcs_organization).not_to receive(:restore) + end end end end diff --git a/spec/travis/remote_vcs/organization_spec.rb b/spec/travis/remote_vcs/organization_spec.rb index 5750f2a52..f65a57598 100644 --- a/spec/travis/remote_vcs/organization_spec.rb +++ b/spec/travis/remote_vcs/organization_spec.rb @@ -19,16 +19,9 @@ it { is_expected.to be true } end - context 'when the request fails' do - let!(:request) do - stub_request(:delete, /http.*\/organizations\/#{org_id}/) - .to_return(status: 500) - end - - it 'returns false' do - expect(subject).to be false - end + before { allow(client).to receive(:request).and_return(false) } + it { is_expected.to be false } end end end diff --git a/spec/travis/remote_vcs/repository_spec.rb b/spec/travis/remote_vcs/repository_spec.rb index 72a570b91..04d1ec481 100644 --- a/spec/travis/remote_vcs/repository_spec.rb +++ b/spec/travis/remote_vcs/repository_spec.rb @@ -81,7 +81,7 @@ end describe '#destroy' do - subject { repository.destroy(repository_id: id) } + subject { repository.destroy(repository_id: id, vcs_type: 'AssemblaRepository') } context 'when the request is successful' do let!(:request) do