diff --git a/lib/fastlane/plugin/mango/helper/docker_commander.rb b/lib/fastlane/plugin/mango/helper/docker_commander.rb index 2f82ed6..7aed5b0 100644 --- a/lib/fastlane/plugin/mango/helper/docker_commander.rb +++ b/lib/fastlane/plugin/mango/helper/docker_commander.rb @@ -6,7 +6,9 @@ module Helper module DockerCommander def self.pull_image(docker_image_name:) - Actions.sh("docker pull #{docker_image_name}") + handle_thin_pool_exception do + Actions.sh("docker pull #{docker_image_name}") + end end def self.start_container(emulator_args:, docker_name:, docker_image:) @@ -19,7 +21,9 @@ def self.start_container(emulator_args:, docker_name:, docker_image:) # Action.sh returns all output that the command produced but we are only # interested in the last line, since it contains the id of the created container. UI.important("Attaching #{ENV['PWD']} to the docker container") - Actions.sh("docker run -v $PWD:/root/tests --privileged -t -d #{emulator_args} #{docker_name} #{docker_image}").chomp + handle_thin_pool_exception do + Actions.sh("docker run -v $PWD:/root/tests --privileged -t -d #{emulator_args} #{docker_name} #{docker_image}").chomp + end end def self.stop_container(container_name:) @@ -36,10 +40,27 @@ def self.disconnect_network_bridge(container_name:) # Do nothing if the network bridge is already gone end + def self.prune + Action.sh('docker system prune -f') + end + + def self.handle_thin_pool_exception(&block) + begin + block.call + rescue FastlaneCore::Interface::FastlaneShellError => exception + retry_counter = retry_counter.to_i + 1 + if exception.message =~ /Create more free space in thin pool/ && retry_counter < 2 + prune + retry + else + raise exception + end + end + end + def self.docker_exec(command:, container_name:) Actions.sh("docker exec -i #{container_name} bash -l -c \"#{command}\"") if container_name end - end end -end +end \ No newline at end of file diff --git a/spec/docker_commander_spec.rb b/spec/docker_commander_spec.rb index 716c9a9..7da12b5 100644 --- a/spec/docker_commander_spec.rb +++ b/spec/docker_commander_spec.rb @@ -62,6 +62,38 @@ end end + describe '#handle_thin_pool_exception' do + it 'Raises when exception message is not related to thin pool' do + expect { + @docker_commander.handle_thin_pool_exception do + raise FastlaneCore::Interface::FastlaneShellError, 'some message' + end + }.to raise_error(FastlaneCore::Interface::FastlaneShellError, 'some message') + end + + it 'Retries the command when the message is related to thin pool and raise if it fails after retry' do + expect(Fastlane::Actions).to receive(:sh).twice.with('test') + + expect { + @docker_commander.handle_thin_pool_exception do + Fastlane::Actions.sh('test') + raise FastlaneCore::Interface::FastlaneShellError, 'Create more free space in thin pool or ...' + end + }.to raise_exception(FastlaneCore::Interface::FastlaneShellError) + end + + it 'Calls prune just once when the message is related to thin pool and raise if initial command fails' do + expect(@docker_commander).to receive(:prune).once + + expect { + @docker_commander.handle_thin_pool_exception do + raise FastlaneCore::Interface::FastlaneShellError, 'Create more free space in thin pool or ...' + end + }.to raise_exception(FastlaneCore::Interface::FastlaneShellError) + end + + end + describe '#docker_exec' do it 'executes commands inside docker if container name is specified' do expect(Fastlane::Actions).to receive(:sh).with("docker exec -i my_container bash -l -c \"do stuff\"") @@ -73,4 +105,5 @@ @docker_commander.docker_exec(command: 'do stuff', container_name: nil) end end + end