config: Implement for `ignore-from-file` option

Closes https://github.com/adrienverge/yamllint/issues/360
Co-authored-by: Adrien Vergé <@adrienverge>
pull/493/head
andrewnaguib 4 years ago committed by Adrien Vergé
parent fb0c0a5247
commit 2f8ad7003a

@ -190,6 +190,20 @@ Here is a more complex example:
*.ignore-trailing-spaces.yaml *.ignore-trailing-spaces.yaml
ascii-art/* ascii-art/*
You can also use the ``.gitignore`` file (or any list of files) through:
.. code-block:: yaml
ignore-from-file: .gitignore
or:
.. code-block:: yaml
ignore-from-file: [.gitignore, .yamlignore]
.. note:: However, this is mutually exclusive with the ``ignore`` key.
Setting the locale Setting the locale
------------------ ------------------

@ -22,6 +22,7 @@ import unittest
from tests.common import build_temp_workspace from tests.common import build_temp_workspace
from yamllint.config import YamlLintConfigError
from yamllint import cli from yamllint import cli
from yamllint import config from yamllint import config
@ -429,10 +430,10 @@ class ExtendedLibraryConfigTestCase(unittest.TestCase):
self.assertEqual(new.rules['empty-lines']['max-end'], 0) self.assertEqual(new.rules['empty-lines']['max-end'], 0)
class IgnorePathConfigTestCase(unittest.TestCase): class IgnoreConfigTestCase(unittest.TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
super(IgnorePathConfigTestCase, cls).setUpClass() super().setUpClass()
bad_yaml = ('---\n' bad_yaml = ('---\n'
'- key: val1\n' '- key: val1\n'
@ -452,14 +453,99 @@ class IgnorePathConfigTestCase(unittest.TestCase):
's/s/ign-trail/file.yaml': bad_yaml, 's/s/ign-trail/file.yaml': bad_yaml,
's/s/ign-trail/s/s/file.yaml': bad_yaml, 's/s/ign-trail/s/s/file.yaml': bad_yaml,
's/s/ign-trail/s/s/file2.lint-me-anyway.yaml': bad_yaml, 's/s/ign-trail/s/s/file2.lint-me-anyway.yaml': bad_yaml,
})
cls.backup_wd = os.getcwd()
os.chdir(cls.wd)
@classmethod
def tearDownClass(cls):
super().tearDownClass()
os.chdir(cls.backup_wd)
'.yamllint': 'ignore: |\n' shutil.rmtree(cls.wd)
def test_mutually_exclusive_ignore_keys(self):
self.assertRaises(
YamlLintConfigError,
config.YamlLintConfig, 'extends: default\n'
'ignore-from-file: .gitignore\n'
'ignore: |\n'
' *.dont-lint-me.yaml\n'
' /bin/\n')
def test_ignore_from_file_not_exist(self):
self.assertRaises(
FileNotFoundError,
config.YamlLintConfig, 'extends: default\n'
'ignore-from-file: not_found_file\n')
def test_ignore_from_file_incorrect_type(self):
self.assertRaises(
YamlLintConfigError,
config.YamlLintConfig, 'extends: default\n'
'ignore-from-file: 0\n')
self.assertRaises(
YamlLintConfigError,
config.YamlLintConfig, 'extends: default\n'
'ignore-from-file: [0]\n')
def test_no_ignore(self):
sys.stdout = StringIO()
with self.assertRaises(SystemExit):
cli.run(('-f', 'parsable', '.'))
out = sys.stdout.getvalue()
out = '\n'.join(sorted(out.splitlines()))
keydup = '[error] duplication of key "key" in mapping (key-duplicates)'
trailing = '[error] trailing spaces (trailing-spaces)'
hyphen = '[error] too many spaces after hyphen (hyphens)'
self.assertEqual(out, '\n'.join((
'./bin/file.lint-me-anyway.yaml:3:3: ' + keydup,
'./bin/file.lint-me-anyway.yaml:4:17: ' + trailing,
'./bin/file.lint-me-anyway.yaml:5:5: ' + hyphen,
'./bin/file.yaml:3:3: ' + keydup,
'./bin/file.yaml:4:17: ' + trailing,
'./bin/file.yaml:5:5: ' + hyphen,
'./file-at-root.yaml:3:3: ' + keydup,
'./file-at-root.yaml:4:17: ' + trailing,
'./file-at-root.yaml:5:5: ' + hyphen,
'./file.dont-lint-me.yaml:3:3: ' + keydup,
'./file.dont-lint-me.yaml:4:17: ' + trailing,
'./file.dont-lint-me.yaml:5:5: ' + hyphen,
'./ign-dup/file.yaml:3:3: ' + keydup,
'./ign-dup/file.yaml:4:17: ' + trailing,
'./ign-dup/file.yaml:5:5: ' + hyphen,
'./ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./ign-trail/file.yaml:3:3: ' + keydup,
'./ign-trail/file.yaml:4:17: ' + trailing,
'./ign-trail/file.yaml:5:5: ' + hyphen,
'./include/ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./include/ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./include/ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen,
)))
def test_run_with_ignore(self):
with open(os.path.join(self.wd, '.yamllint'), 'w') as f:
f.write('extends: default\n'
'ignore: |\n'
' *.dont-lint-me.yaml\n' ' *.dont-lint-me.yaml\n'
' /bin/\n' ' /bin/\n'
' !/bin/*.lint-me-anyway.yaml\n' ' !/bin/*.lint-me-anyway.yaml\n'
'\n'
'extends: default\n'
'\n'
'rules:\n' 'rules:\n'
' key-duplicates:\n' ' key-duplicates:\n'
' ignore: |\n' ' ignore: |\n'
@ -467,21 +553,108 @@ class IgnorePathConfigTestCase(unittest.TestCase):
' trailing-spaces:\n' ' trailing-spaces:\n'
' ignore: |\n' ' ignore: |\n'
' ign-trail\n' ' ign-trail\n'
' !*.lint-me-anyway.yaml\n', ' !*.lint-me-anyway.yaml\n')
})
cls.backup_wd = os.getcwd() sys.stdout = StringIO()
os.chdir(cls.wd) with self.assertRaises(SystemExit):
cli.run(('-f', 'parsable', '.'))
@classmethod out = sys.stdout.getvalue()
def tearDownClass(cls): out = '\n'.join(sorted(out.splitlines()))
super(IgnorePathConfigTestCase, cls).tearDownClass()
os.chdir(cls.backup_wd) docstart = '[warning] missing document start "---" (document-start)'
keydup = '[error] duplication of key "key" in mapping (key-duplicates)'
trailing = '[error] trailing spaces (trailing-spaces)'
hyphen = '[error] too many spaces after hyphen (hyphens)'
shutil.rmtree(cls.wd) self.assertEqual(out, '\n'.join((
'./.yamllint:1:1: ' + docstart,
'./bin/file.lint-me-anyway.yaml:3:3: ' + keydup,
'./bin/file.lint-me-anyway.yaml:4:17: ' + trailing,
'./bin/file.lint-me-anyway.yaml:5:5: ' + hyphen,
'./file-at-root.yaml:3:3: ' + keydup,
'./file-at-root.yaml:4:17: ' + trailing,
'./file-at-root.yaml:5:5: ' + hyphen,
'./ign-dup/file.yaml:4:17: ' + trailing,
'./ign-dup/file.yaml:5:5: ' + hyphen,
'./ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./ign-trail/file.yaml:3:3: ' + keydup,
'./ign-trail/file.yaml:5:5: ' + hyphen,
'./include/ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./include/ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./include/ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen,
)))
def test_run_with_ignore_from_file(self):
with open(os.path.join(self.wd, '.yamllint'), 'w') as f:
f.write('extends: default\n'
'ignore-from-file: .gitignore\n')
with open(os.path.join(self.wd, '.gitignore'), 'w') as f:
f.write('*.dont-lint-me.yaml\n'
'/bin/\n'
'!/bin/*.lint-me-anyway.yaml\n')
sys.stdout = StringIO()
with self.assertRaises(SystemExit):
cli.run(('-f', 'parsable', '.'))
out = sys.stdout.getvalue()
out = '\n'.join(sorted(out.splitlines()))
docstart = '[warning] missing document start "---" (document-start)'
keydup = '[error] duplication of key "key" in mapping (key-duplicates)'
trailing = '[error] trailing spaces (trailing-spaces)'
hyphen = '[error] too many spaces after hyphen (hyphens)'
self.assertEqual(out, '\n'.join((
'./.yamllint:1:1: ' + docstart,
'./bin/file.lint-me-anyway.yaml:3:3: ' + keydup,
'./bin/file.lint-me-anyway.yaml:4:17: ' + trailing,
'./bin/file.lint-me-anyway.yaml:5:5: ' + hyphen,
'./file-at-root.yaml:3:3: ' + keydup,
'./file-at-root.yaml:4:17: ' + trailing,
'./file-at-root.yaml:5:5: ' + hyphen,
'./ign-dup/file.yaml:3:3: ' + keydup,
'./ign-dup/file.yaml:4:17: ' + trailing,
'./ign-dup/file.yaml:5:5: ' + hyphen,
'./ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./ign-trail/file.yaml:3:3: ' + keydup,
'./ign-trail/file.yaml:4:17: ' + trailing,
'./ign-trail/file.yaml:5:5: ' + hyphen,
'./include/ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./include/ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./include/ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen,
)))
def test_run_with_ignored_from_file(self):
with open(os.path.join(self.wd, '.yamllint'), 'w') as f:
f.write('ignore-from-file: [.gitignore, .yamlignore]\n'
'extends: default\n')
with open(os.path.join(self.wd, '.gitignore'), 'w') as f:
f.write('*.dont-lint-me.yaml\n'
'/bin/\n')
with open(os.path.join(self.wd, '.yamlignore'), 'w') as f:
f.write('!/bin/*.lint-me-anyway.yaml\n')
def test_run_with_ignored_path(self):
sys.stdout = StringIO() sys.stdout = StringIO()
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
cli.run(('-f', 'parsable', '.')) cli.run(('-f', 'parsable', '.'))
@ -502,18 +675,23 @@ class IgnorePathConfigTestCase(unittest.TestCase):
'./file-at-root.yaml:3:3: ' + keydup, './file-at-root.yaml:3:3: ' + keydup,
'./file-at-root.yaml:4:17: ' + trailing, './file-at-root.yaml:4:17: ' + trailing,
'./file-at-root.yaml:5:5: ' + hyphen, './file-at-root.yaml:5:5: ' + hyphen,
'./ign-dup/file.yaml:3:3: ' + keydup,
'./ign-dup/file.yaml:4:17: ' + trailing, './ign-dup/file.yaml:4:17: ' + trailing,
'./ign-dup/file.yaml:5:5: ' + hyphen, './ign-dup/file.yaml:5:5: ' + hyphen,
'./ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./ign-dup/sub/dir/file.yaml:4:17: ' + trailing, './ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./ign-dup/sub/dir/file.yaml:5:5: ' + hyphen, './ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./ign-trail/file.yaml:3:3: ' + keydup, './ign-trail/file.yaml:3:3: ' + keydup,
'./ign-trail/file.yaml:4:17: ' + trailing,
'./ign-trail/file.yaml:5:5: ' + hyphen, './ign-trail/file.yaml:5:5: ' + hyphen,
'./include/ign-dup/sub/dir/file.yaml:3:3: ' + keydup, './include/ign-dup/sub/dir/file.yaml:3:3: ' + keydup,
'./include/ign-dup/sub/dir/file.yaml:4:17: ' + trailing, './include/ign-dup/sub/dir/file.yaml:4:17: ' + trailing,
'./include/ign-dup/sub/dir/file.yaml:5:5: ' + hyphen, './include/ign-dup/sub/dir/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/file.yaml:3:3: ' + keydup, './s/s/ign-trail/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/file.yaml:5:5: ' + hyphen, './s/s/ign-trail/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file.yaml:3:3: ' + keydup, './s/s/ign-trail/s/s/file.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file.yaml:4:17: ' + trailing,
'./s/s/ign-trail/s/s/file.yaml:5:5: ' + hyphen, './s/s/ign-trail/s/s/file.yaml:5:5: ' + hyphen,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:3:3: ' + keydup, './s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:3:3: ' + keydup,
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing, './s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:4:17: ' + trailing,

@ -13,6 +13,7 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import fileinput
import os.path import os.path
import pathspec import pathspec
@ -96,7 +97,21 @@ class YamlLintConfig:
except Exception as e: except Exception as e:
raise YamlLintConfigError('invalid config: %s' % e) raise YamlLintConfigError('invalid config: %s' % e)
if 'ignore' in conf: if 'ignore' in conf and 'ignore-from-file' in conf:
raise YamlLintConfigError(
'invalid config: ignore and ignore-from-file keys cannot be '
'used together')
elif 'ignore-from-file' in conf:
if isinstance(conf['ignore-from-file'], str):
conf['ignore-from-file'] = [conf['ignore-from-file']]
if not (isinstance(conf['ignore-from-file'], list) and all(
isinstance(ln, str) for ln in conf['ignore-from-file'])):
raise YamlLintConfigError(
'invalid config: ignore-from-file should contain '
'filename(s), either as a list or string')
with fileinput.input(conf['ignore-from-file']) as f:
self.ignore = pathspec.PathSpec.from_lines('gitwildmatch', f)
elif 'ignore' in conf:
if not isinstance(conf['ignore'], str): if not isinstance(conf['ignore'], str):
raise YamlLintConfigError( raise YamlLintConfigError(
'invalid config: ignore should contain file patterns') 'invalid config: ignore should contain file patterns')
@ -150,7 +165,7 @@ def validate_rule_conf(rule, conf):
options = getattr(rule, 'CONF', {}) options = getattr(rule, 'CONF', {})
options_default = getattr(rule, 'DEFAULT', {}) options_default = getattr(rule, 'DEFAULT', {})
for optkey in conf: for optkey in conf:
if optkey in ('ignore', 'level'): if optkey in ('ignore', 'ignore-from-file', 'level'):
continue continue
if optkey not in options: if optkey not in options:
raise YamlLintConfigError( raise YamlLintConfigError(

Loading…
Cancel
Save