diff --git a/docs/configuration.rst b/docs/configuration.rst index c1d979ca..9aeecbe2 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -140,7 +140,8 @@ Ignoring paths -------------- It is possible to exclude specific files or directories, so that the linter -doesn't process them. +doesn't process them. They can be provided either as a list of paths, or as a +bulk string. You can either totally ignore files (they won't be looked at): @@ -153,6 +154,13 @@ You can either totally ignore files (they won't be looked at): all/this/directory/ *.template.yaml + # or: + + ignore: + - /this/specific/file.yaml + - all/this/directory/ + - '*.template.yaml' + or ignore paths only for specific rules: .. code-block:: yaml @@ -165,6 +173,14 @@ or ignore paths only for specific rules: /this-file-has-trailing-spaces-but-it-is-OK.yaml /generated/*.yaml + # or: + + rules: + trailing-spaces: + ignore: + - /this-file-has-trailing-spaces-but-it-is-OK.yaml + - /generated/*.yaml + Note that this ``.gitignore``-style path pattern allows complex path exclusion/inclusion, see the `pathspec README file `_ for more details. diff --git a/tests/test_config.py b/tests/test_config.py index 1e6c1c77..8e90246d 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -369,7 +369,7 @@ def test_extend_recursive_default_values(self): self.assertEqual(c.rules['colons']['max-spaces-before'], 0) self.assertEqual(c.rules['colons']['max-spaces-after'], 1) - def test_extended_ignore(self): + def test_extended_ignore_str(self): with tempfile.NamedTemporaryFile('w') as f: f.write('ignore: |\n' ' *.template.yaml\n') @@ -379,6 +379,16 @@ def test_extended_ignore(self): self.assertEqual(c.ignore.match_file('test.template.yaml'), True) self.assertEqual(c.ignore.match_file('test.yaml'), False) + def test_extended_ignore_list(self): + with tempfile.NamedTemporaryFile('w') as f: + f.write('ignore:\n' + ' - "*.template.yaml"\n') + f.flush() + c = config.YamlLintConfig('extends: ' + f.name + '\n') + + self.assertEqual(c.ignore.match_file('test.template.yaml'), True) + self.assertEqual(c.ignore.match_file('test.yaml'), False) + class ExtendedLibraryConfigTestCase(unittest.TestCase): def test_extend_config_disable_rule(self): @@ -539,7 +549,7 @@ def test_no_ignore(self): './s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen, ))) - def test_run_with_ignore(self): + def test_run_with_ignore_str(self): with open(os.path.join(self.wd, '.yamllint'), 'w') as f: f.write('extends: default\n' 'ignore: |\n' @@ -593,6 +603,60 @@ def test_run_with_ignore(self): './s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen, ))) + def test_run_with_ignore_list(self): + with open(os.path.join(self.wd, '.yamllint'), 'w') as f: + f.write('extends: default\n' + 'ignore:\n' + ' - "*.dont-lint-me.yaml"\n' + ' - "/bin/"\n' + ' - "!/bin/*.lint-me-anyway.yaml"\n' + 'rules:\n' + ' key-duplicates:\n' + ' ignore:\n' + ' - "/ign-dup"\n' + ' trailing-spaces:\n' + ' ignore:\n' + ' - "ign-trail"\n' + ' - "!*.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: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' diff --git a/yamllint/config.py b/yamllint/config.py index 3bee7918..a5ef405e 100644 --- a/yamllint/config.py +++ b/yamllint/config.py @@ -112,11 +112,16 @@ def parse(self, raw_content): 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 isinstance(conf['ignore'], str): + self.ignore = pathspec.PathSpec.from_lines( + 'gitwildmatch', conf['ignore'].splitlines()) + elif (isinstance(conf['ignore'], list) and + all(isinstance(line, str) for line in conf['ignore'])): + self.ignore = pathspec.PathSpec.from_lines( + 'gitwildmatch', conf['ignore']) + else: raise YamlLintConfigError( 'invalid config: ignore should contain file patterns') - self.ignore = pathspec.PathSpec.from_lines( - 'gitwildmatch', conf['ignore'].splitlines()) if 'yaml-files' in conf: if not (isinstance(conf['yaml-files'], list) @@ -150,11 +155,16 @@ def validate_rule_conf(rule, conf): if isinstance(conf, dict): if ('ignore' in conf and not isinstance(conf['ignore'], pathspec.pathspec.PathSpec)): - if not isinstance(conf['ignore'], str): + if isinstance(conf['ignore'], str): + conf['ignore'] = pathspec.PathSpec.from_lines( + 'gitwildmatch', conf['ignore'].splitlines()) + elif (isinstance(conf['ignore'], list) and + all(isinstance(line, str) for line in conf['ignore'])): + conf['ignore'] = pathspec.PathSpec.from_lines( + 'gitwildmatch', conf['ignore']) + else: raise YamlLintConfigError( 'invalid config: ignore should contain file patterns') - conf['ignore'] = pathspec.PathSpec.from_lines( - 'gitwildmatch', conf['ignore'].splitlines()) if 'level' not in conf: conf['level'] = 'error'