Do not treat Borg warnings (exit code 1) as failures (#204).
This commit is contained in:
parent
a7cc2ea803
commit
ccbd0b608b
6 changed files with 41 additions and 6 deletions
1
NEWS
1
NEWS
|
@ -1,4 +1,5 @@
|
||||||
1.3.14
|
1.3.14
|
||||||
|
* #204: Do not treat Borg warnings (exit code 1) as failures.
|
||||||
* When validating configuration files, require strings instead of allowing any scalar type.
|
* When validating configuration files, require strings instead of allowing any scalar type.
|
||||||
|
|
||||||
1.3.13
|
1.3.13
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import logging
|
import logging
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from borgmatic.execute import execute_command
|
from borgmatic.execute import BORG_ERROR_EXIT_CODE, execute_command
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -44,4 +44,8 @@ def initialize_repository(
|
||||||
)
|
)
|
||||||
|
|
||||||
# Don't use execute_command() here because it doesn't support interactive prompts.
|
# Don't use execute_command() here because it doesn't support interactive prompts.
|
||||||
|
try:
|
||||||
subprocess.check_call(init_command)
|
subprocess.check_call(init_command)
|
||||||
|
except subprocess.CalledProcessError as error:
|
||||||
|
if error.returncode >= BORG_ERROR_EXIT_CODE:
|
||||||
|
raise
|
||||||
|
|
|
@ -5,6 +5,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
ERROR_OUTPUT_MAX_LINE_COUNT = 25
|
ERROR_OUTPUT_MAX_LINE_COUNT = 25
|
||||||
|
BORG_ERROR_EXIT_CODE = 2
|
||||||
|
|
||||||
|
|
||||||
def execute_and_log_output(full_command, output_log_level, shell):
|
def execute_and_log_output(full_command, output_log_level, shell):
|
||||||
|
@ -31,7 +32,7 @@ def execute_and_log_output(full_command, output_log_level, shell):
|
||||||
logger.log(output_log_level, remaining_output)
|
logger.log(output_log_level, remaining_output)
|
||||||
|
|
||||||
exit_code = process.poll()
|
exit_code = process.poll()
|
||||||
if exit_code != 0:
|
if exit_code >= BORG_ERROR_EXIT_CODE:
|
||||||
# If an error occurs, include its output in the raised exception so that we don't
|
# If an error occurs, include its output in the raised exception so that we don't
|
||||||
# inadvertently hide error output.
|
# inadvertently hide error output.
|
||||||
if len(last_lines) == ERROR_OUTPUT_MAX_LINE_COUNT:
|
if len(last_lines) == ERROR_OUTPUT_MAX_LINE_COUNT:
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -1,6 +1,6 @@
|
||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
VERSION = '1.3.13'
|
VERSION = '1.3.14'
|
||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
|
|
@ -15,7 +15,16 @@ def test_execute_and_log_output_logs_each_line_separately():
|
||||||
module.execute_and_log_output(['echo', 'there'], output_log_level=logging.INFO, shell=False)
|
module.execute_and_log_output(['echo', 'there'], output_log_level=logging.INFO, shell=False)
|
||||||
|
|
||||||
|
|
||||||
|
def test_execute_and_log_output_with_borg_warning_does_not_raise():
|
||||||
|
flexmock(module.logger).should_receive('log')
|
||||||
|
|
||||||
|
# Borg's exit code 1 is a warning, not an error.
|
||||||
|
module.execute_and_log_output(['false'], output_log_level=logging.INFO, shell=False)
|
||||||
|
|
||||||
|
|
||||||
def test_execute_and_log_output_includes_borg_error_output_in_exception():
|
def test_execute_and_log_output_includes_borg_error_output_in_exception():
|
||||||
|
flexmock(module.logger).should_receive('log')
|
||||||
|
|
||||||
with pytest.raises(subprocess.CalledProcessError) as error:
|
with pytest.raises(subprocess.CalledProcessError) as error:
|
||||||
module.execute_and_log_output(['grep'], output_log_level=logging.INFO, shell=False)
|
module.execute_and_log_output(['grep'], output_log_level=logging.INFO, shell=False)
|
||||||
|
|
||||||
|
@ -25,6 +34,7 @@ def test_execute_and_log_output_includes_borg_error_output_in_exception():
|
||||||
|
|
||||||
def test_execute_and_log_output_truncates_long_borg_error_output():
|
def test_execute_and_log_output_truncates_long_borg_error_output():
|
||||||
flexmock(module).ERROR_OUTPUT_MAX_LINE_COUNT = 0
|
flexmock(module).ERROR_OUTPUT_MAX_LINE_COUNT = 0
|
||||||
|
flexmock(module.logger).should_receive('log')
|
||||||
|
|
||||||
with pytest.raises(subprocess.CalledProcessError) as error:
|
with pytest.raises(subprocess.CalledProcessError) as error:
|
||||||
module.execute_and_log_output(['grep'], output_log_level=logging.INFO, shell=False)
|
module.execute_and_log_output(['grep'], output_log_level=logging.INFO, shell=False)
|
||||||
|
@ -40,7 +50,7 @@ def test_execute_and_log_output_with_no_output_logs_nothing():
|
||||||
|
|
||||||
|
|
||||||
def test_execute_and_log_output_with_error_exit_status_raises():
|
def test_execute_and_log_output_with_error_exit_status_raises():
|
||||||
flexmock(module.logger).should_receive('log').never()
|
flexmock(module.logger).should_receive('log')
|
||||||
|
|
||||||
with pytest.raises(subprocess.CalledProcessError):
|
with pytest.raises(subprocess.CalledProcessError):
|
||||||
module.execute_and_log_output(['false'], output_log_level=logging.INFO, shell=False)
|
module.execute_and_log_output(['grep'], output_log_level=logging.INFO, shell=False)
|
||||||
|
|
|
@ -35,6 +35,25 @@ def test_initialize_repository_calls_borg_with_parameters():
|
||||||
module.initialize_repository(repository='repo', encryption_mode='repokey')
|
module.initialize_repository(repository='repo', encryption_mode='repokey')
|
||||||
|
|
||||||
|
|
||||||
|
def test_initialize_repository_does_not_raise_for_borg_init_warning():
|
||||||
|
insert_info_command_not_found_mock()
|
||||||
|
flexmock(module.subprocess).should_receive('check_call').and_raise(
|
||||||
|
module.subprocess.CalledProcessError(1, 'borg init')
|
||||||
|
)
|
||||||
|
|
||||||
|
module.initialize_repository(repository='repo', encryption_mode='repokey')
|
||||||
|
|
||||||
|
|
||||||
|
def test_initialize_repository_raises_for_borg_init_error():
|
||||||
|
insert_info_command_not_found_mock()
|
||||||
|
flexmock(module.subprocess).should_receive('check_call').and_raise(
|
||||||
|
module.subprocess.CalledProcessError(2, 'borg init')
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(subprocess.CalledProcessError):
|
||||||
|
module.initialize_repository(repository='repo', encryption_mode='repokey')
|
||||||
|
|
||||||
|
|
||||||
def test_initialize_repository_skips_initialization_when_repository_already_exists():
|
def test_initialize_repository_skips_initialization_when_repository_already_exists():
|
||||||
insert_info_command_found_mock()
|
insert_info_command_found_mock()
|
||||||
flexmock(module.subprocess).should_receive('check_call').never()
|
flexmock(module.subprocess).should_receive('check_call').never()
|
||||||
|
|
Loading…
Reference in a new issue