diff --git a/NEWS b/NEWS index 44658e2ad..66b3c739b 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +1.3.3 + * Add validate-borgmatic-config command, useful for validating borgmatic config generated by + configuration management or even edited by hand. + 1.3.2 * #160: Fix for hooks executing when using --dry-run. Now hooks are skipped during a dry run. diff --git a/borgmatic/commands/validate_config.py b/borgmatic/commands/validate_config.py index c7aef4b6c..a53c146a8 100644 --- a/borgmatic/commands/validate_config.py +++ b/borgmatic/commands/validate_config.py @@ -42,9 +42,7 @@ def main(): # pragma: no cover found_issues = False for config_filename in config_filenames: try: - validate.parse_configuration( - config_filename, validate.schema_filename() - ) + validate.parse_configuration(config_filename, validate.schema_filename()) except (ValueError, OSError, validate.Validation_error) as error: logging.critical('{}: Error parsing configuration file'.format(config_filename)) logging.critical(error) @@ -53,4 +51,6 @@ def main(): # pragma: no cover if found_issues: sys.exit(1) else: - logger.info('All given configuration files are valid: {}'.format(config_filenames)) + logger.info( + 'All given configuration files are valid: {}'.format(', '.join(config_filenames)) + ) diff --git a/docs/how-to/set-up-backups.md b/docs/how-to/set-up-backups.md index f0d3a9cb8..c1cbd2181 100644 --- a/docs/how-to/set-up-backups.md +++ b/docs/how-to/set-up-backups.md @@ -76,7 +76,21 @@ FAQ](http://borgbackup.readthedocs.io/en/stable/faq.html#how-can-i-specify-the-e for more info. -### +### Validation + +If you'd like to validate that your borgmatic configuration is valid, the +following command is available for that: + +```bash +sudo validate-borgmatic-config +``` + +This command's exit status (`$?` in Bash) is zero when configuration is valid +and non-zero otherwise. + +Validating configuration can be useful if you generate your configuration +files via configuration management, or you just want to double check that your +hand edits are valid. ## Initialization diff --git a/setup.py b/setup.py index 76d391b35..d49e93300 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ from setuptools import setup, find_packages -VERSION = '1.3.2' +VERSION = '1.3.3' setup( diff --git a/tests/end-to-end/test_borgmatic.py b/tests/end-to-end/test_borgmatic.py index 408792652..620e67a96 100644 --- a/tests/end-to-end/test_borgmatic.py +++ b/tests/end-to-end/test_borgmatic.py @@ -29,36 +29,6 @@ def generate_configuration(config_path, repository_path): config_file.close() -def validate_valid_configuration(config_path): - ''' - Validate borgmatic configuration which is valid. - ''' - subprocess.check_call( - 'validate-borgmatic-config --config {}'.format(config_path).split(' ') - ) - - -def validate_invalid_configuration(config_path): - ''' - Validate borgmatic configuration which is invalid. - ''' - - config = ( - open(config_path) - .read() - .replace('keep_daily: 7', 'keep_daily: "7"') - ) - config_file = open(config_path, 'w') - config_file.write(config) - config_file.close() - - exit_code = subprocess.call( - 'validate-borgmatic-config --config {}'.format(config_path).split(' ') - ) - - assert exit_code == 1 - - def test_borgmatic_command(): # Create a Borg repository. temporary_directory = tempfile.mkdtemp() @@ -71,11 +41,7 @@ def test_borgmatic_command(): try: config_path = os.path.join(temporary_directory, 'test.yaml') - invalid_config_path = os.path.join(temporary_directory, 'test_invalid.yaml') generate_configuration(config_path, repository_path) - generate_configuration(invalid_config_path, repository_path) - validate_valid_configuration(config_path) - validate_invalid_configuration(invalid_config_path) subprocess.check_call( 'borgmatic -v 2 --config {} --init --encryption repokey'.format(config_path).split(' ') diff --git a/tests/end-to-end/test_validate_config.py b/tests/end-to-end/test_validate_config.py new file mode 100644 index 000000000..5de83a395 --- /dev/null +++ b/tests/end-to-end/test_validate_config.py @@ -0,0 +1,36 @@ +import os +import subprocess +import tempfile + + +def test_validate_config_command_with_valid_configuration_succeeds(): + with tempfile.TemporaryDirectory() as temporary_directory: + config_path = os.path.join(temporary_directory, 'test.yaml') + + subprocess.check_call( + 'generate-borgmatic-config --destination {}'.format(config_path).split(' ') + ) + exit_code = subprocess.call( + 'validate-borgmatic-config --config {}'.format(config_path).split(' ') + ) + + assert exit_code == 0 + + +def test_validate_config_command_with_invalid_configuration_fails(): + with tempfile.TemporaryDirectory() as temporary_directory: + config_path = os.path.join(temporary_directory, 'test.yaml') + + subprocess.check_call( + 'generate-borgmatic-config --destination {}'.format(config_path).split(' ') + ) + config = open(config_path).read().replace('keep_daily: 7', 'keep_daily: "7"') + config_file = open(config_path, 'w') + config_file.write(config) + config_file.close() + + exit_code = subprocess.call( + 'validate-borgmatic-config --config {}'.format(config_path).split(' ') + ) + + assert exit_code == 1 diff --git a/tests/integration/commands/test_validate_config.py b/tests/integration/commands/test_validate_config.py new file mode 100644 index 000000000..cb0144d29 --- /dev/null +++ b/tests/integration/commands/test_validate_config.py @@ -0,0 +1,20 @@ +from flexmock import flexmock + +from borgmatic.commands import validate_config as module + + +def test_parse_arguments_with_no_arguments_uses_defaults(): + config_paths = ['default'] + flexmock(module.collect).should_receive('get_default_config_paths').and_return(config_paths) + + parser = module.parse_arguments() + + assert parser.config_paths == config_paths + + +def test_parse_arguments_with_multiple_config_paths_parses_as_list(): + flexmock(module.collect).should_receive('get_default_config_paths').and_return(['default']) + + parser = module.parse_arguments('--config', 'myconfig', 'otherconfig') + + assert parser.config_paths == ['myconfig', 'otherconfig']