Add error info if tabs are found in the yaml (#18343)
If a yaml file fails to load because of tabs being used for formatting, detect that and show a error message with more details.
This commit is contained in:
parent
e8e09f3df6
commit
51e3ef89a9
4 changed files with 41 additions and 1 deletions
|
@ -24,7 +24,8 @@ from ansible.errors.yaml_strings import ( YAML_POSITION_DETAILS,
|
||||||
YAML_COMMON_DICT_ERROR,
|
YAML_COMMON_DICT_ERROR,
|
||||||
YAML_COMMON_UNQUOTED_COLON_ERROR,
|
YAML_COMMON_UNQUOTED_COLON_ERROR,
|
||||||
YAML_COMMON_PARTIALLY_QUOTED_LINE_ERROR,
|
YAML_COMMON_PARTIALLY_QUOTED_LINE_ERROR,
|
||||||
YAML_COMMON_UNBALANCED_QUOTES_ERROR )
|
YAML_COMMON_UNBALANCED_QUOTES_ERROR,
|
||||||
|
YAML_COMMON_LEADING_TAB_ERROR)
|
||||||
from ansible.module_utils._text import to_native, to_text
|
from ansible.module_utils._text import to_native, to_text
|
||||||
|
|
||||||
|
|
||||||
|
@ -111,6 +112,9 @@ class AnsibleError(Exception):
|
||||||
#header_line = ("=" * 73)
|
#header_line = ("=" * 73)
|
||||||
error_message += "\nThe offending line appears to be:\n\n%s\n%s\n%s\n" % (prev_line.rstrip(), target_line.rstrip(), arrow_line)
|
error_message += "\nThe offending line appears to be:\n\n%s\n%s\n%s\n" % (prev_line.rstrip(), target_line.rstrip(), arrow_line)
|
||||||
|
|
||||||
|
# TODO: There may be cases where there is a valid tab in a line that has other errors.
|
||||||
|
if '\t' in target_line:
|
||||||
|
error_message += YAML_COMMON_LEADING_TAB_ERROR
|
||||||
# common error/remediation checking here:
|
# common error/remediation checking here:
|
||||||
# check for unquoted vars starting lines
|
# check for unquoted vars starting lines
|
||||||
if ('{{' in target_line and '}}' in target_line) and ('"{{' not in target_line or "'{{" not in target_line):
|
if ('{{' in target_line and '}}' in target_line) and ('"{{' not in target_line or "'{{" not in target_line):
|
||||||
|
|
|
@ -116,3 +116,20 @@ Could be written as:
|
||||||
foo: '"bad" "wolf"'
|
foo: '"bad" "wolf"'
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
YAML_COMMON_LEADING_TAB_ERROR = """\
|
||||||
|
There appears to be a tab character at the start of the line.
|
||||||
|
|
||||||
|
YAML does not use tabs for formatting. Tabs should be replaced with spaces.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
- name: update tooling
|
||||||
|
vars:
|
||||||
|
version: 1.2.3
|
||||||
|
# ^--- there is a tab there.
|
||||||
|
|
||||||
|
Should be written as:
|
||||||
|
- name: update tooling
|
||||||
|
vars:
|
||||||
|
version: 1.2.3
|
||||||
|
# ^--- all spaces here.
|
||||||
|
"""
|
||||||
|
|
|
@ -24,6 +24,7 @@ from six import PY3
|
||||||
from ansible.compat.tests import unittest
|
from ansible.compat.tests import unittest
|
||||||
from ansible.compat.tests.mock import patch, mock_open
|
from ansible.compat.tests.mock import patch, mock_open
|
||||||
from ansible.errors import AnsibleParserError
|
from ansible.errors import AnsibleParserError
|
||||||
|
from ansible.errors import yaml_strings
|
||||||
|
|
||||||
from ansible.parsing.dataloader import DataLoader
|
from ansible.parsing.dataloader import DataLoader
|
||||||
|
|
||||||
|
@ -60,6 +61,17 @@ class TestDataLoader(unittest.TestCase):
|
||||||
""", True)
|
""", True)
|
||||||
self.assertRaises(AnsibleParserError, self._loader.load_from_file, 'dummy_yaml_bad.txt')
|
self.assertRaises(AnsibleParserError, self._loader.load_from_file, 'dummy_yaml_bad.txt')
|
||||||
|
|
||||||
|
@patch('ansible.errors.AnsibleError._get_error_lines_from_file')
|
||||||
|
@patch.object(DataLoader, '_get_file_contents')
|
||||||
|
def test_tab_error(self, mock_def, mock_get_error_lines):
|
||||||
|
mock_def.return_value = (u"""---\nhosts: localhost\nvars:\n foo: bar\n\tblip: baz""", True)
|
||||||
|
mock_get_error_lines.return_value = ('''\tblip: baz''', '''..foo: bar''')
|
||||||
|
with self.assertRaises(AnsibleParserError) as cm:
|
||||||
|
self._loader.load_from_file('dummy_yaml_text.txt')
|
||||||
|
self.assertIn(yaml_strings.YAML_COMMON_LEADING_TAB_ERROR, str(cm.exception))
|
||||||
|
self.assertIn('foo: bar', str(cm.exception))
|
||||||
|
|
||||||
|
|
||||||
class TestDataLoaderWithVault(unittest.TestCase):
|
class TestDataLoaderWithVault(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -37,8 +37,10 @@ from units.mock.yaml_helper import YamlTestUtils
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from _yaml import ParserError
|
from _yaml import ParserError
|
||||||
|
from _yaml import ScannerError
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from yaml.parser import ParserError
|
from yaml.parser import ParserError
|
||||||
|
from yaml.scanner import ScannerError
|
||||||
|
|
||||||
|
|
||||||
class NameStringIO(StringIO):
|
class NameStringIO(StringIO):
|
||||||
|
@ -145,6 +147,11 @@ class TestAnsibleLoaderBasic(unittest.TestCase):
|
||||||
loader = AnsibleLoader(stream, 'myfile.yml')
|
loader = AnsibleLoader(stream, 'myfile.yml')
|
||||||
self.assertRaises(ParserError, loader.get_single_data)
|
self.assertRaises(ParserError, loader.get_single_data)
|
||||||
|
|
||||||
|
def test_tab_error(self):
|
||||||
|
stream = StringIO(u"""---\nhosts: localhost\nvars:\n foo: bar\n\tblip: baz""")
|
||||||
|
loader = AnsibleLoader(stream, 'myfile.yml')
|
||||||
|
self.assertRaises(ScannerError, loader.get_single_data)
|
||||||
|
|
||||||
def test_front_matter(self):
|
def test_front_matter(self):
|
||||||
stream = StringIO(u"""---\nfoo: bar""")
|
stream = StringIO(u"""---\nfoo: bar""")
|
||||||
loader = AnsibleLoader(stream, 'myfile.yml')
|
loader = AnsibleLoader(stream, 'myfile.yml')
|
||||||
|
|
Loading…
Reference in a new issue