Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: ignore-from-file relative to config file #701

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ or:
ignore-from-file: [.gitignore, .yamlignore]

.. note:: However, this is mutually exclusive with the ``ignore`` key.
Also, this filepath is considered relative to the config file.

If you need to know the exact list of files that yamllint would process,
without really linting them, you can use ``--list-files``:
Expand Down
91 changes: 91 additions & 0 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,29 @@ def test_ignore_from_file_not_exist(self):
config.YamlLintConfig, 'extends: default\n'
'ignore-from-file: not_found_file\n')

def test_ignore_from_file_exist(self):
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')
parsed = config.YamlLintConfig('extends: default\n'
'ignore-from-file: .gitignore\n')
assert parsed.is_file_ignored("/bin/ignored") is True

def test_ignore_from_file_from_subdir_fails_without_config_file(self):
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')
try:
os.chdir(os.path.join(self.wd, 'bin'))
self.assertRaises(
FileNotFoundError,
config.YamlLintConfig, 'extends: default\n'
'ignore-from-file: .gitignore\n')
finally:
os.chdir(self.wd)

def test_ignore_from_file_incorrect_type(self):
self.assertRaises(
YamlLintConfigError,
Expand Down Expand Up @@ -721,6 +744,74 @@ def test_run_with_ignore_from_file(self):
'./s/s/ign-trail/s/s/file2.lint-me-anyway.yaml:5:5: ' + hyphen,
)))

def test_run_in_subdir_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'
'rules:\n'
' key-duplicates:\n'
' ignore-from-file: .ignore-key-duplicates\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')

with open(os.path.join(self.wd, '.ignore-key-duplicates'), 'w') as f:
f.write('/ign-dup\n')

sys.stdout = StringIO()
try:
os.chdir(os.path.join(self.wd, 'bin'))
with self.assertRaises(SystemExit):
cli.run(('-f', 'parsable', '.'))
finally:
os.chdir(self.wd)

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((
'./file.lint-me-anyway.yaml:3:3: ' + keydup,
'./file.lint-me-anyway.yaml:4:17: ' + trailing,
'./file.lint-me-anyway.yaml:5:5: ' + hyphen,
)))

def test_run_in_subdir_with_ignore_from_file_in_subdir(self):
if os.path.exists(os.path.join(self.wd, '.gitignore')):
os.remove(os.path.join(self.wd, '.gitignore'))
with open(os.path.join(self.wd, '.yamllint'), 'w') as f:
f.write('extends: default\n'
'ignore-from-file: .gitignore\n'
'rules:\n'
' key-duplicates:\n'
' ignore-from-file: .ignore-key-duplicates\n')

with open(os.path.join(self.wd, 'bin', '.gitignore'), 'w') as f:
f.write('*.dont-lint-me.yaml\n'
'/bin/\n'
'!/bin/*.lint-me-anyway.yaml\n')

with open(os.path.join(self.wd, '.ignore-key-duplicates'), 'w') as f:
f.write('/ign-dup\n')

sys.stdout = StringIO()
sys.stderr = StringIO()
try:
os.chdir(os.path.join(self.wd, 'bin'))
with self.assertRaises(FileNotFoundError):
cli.run(('-f', 'parsable', '.'))
finally:
os.chdir(self.wd)

out = sys.stdout.getvalue()

self.assertEqual(out, '')

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'
Expand Down
20 changes: 18 additions & 2 deletions yamllint/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,24 @@ def __init__(self, content=None, file=None):
assert (content is None) ^ (file is None)

self.ignore = None
self.config_dir = None

self.yaml_files = pathspec.PathSpec.from_lines(
'gitwildmatch', ['*.yaml', '*.yml', '.yamllint'])

self.locale = None

if file is not None:
self.config_dir = os.path.dirname(file)
with open(file) as f:
content = f.read()

self.parse(content)
self.validate()

def is_file_ignored(self, filepath):
if self.config_dir:
filepath = os.path.relpath(filepath, start=self.config_dir)
return self.ignore and self.ignore.match_file(filepath)

def is_yaml_file(self, filepath):
Expand Down Expand Up @@ -109,6 +113,11 @@ def parse(self, raw_content):
raise YamlLintConfigError(
'invalid config: ignore-from-file should contain '
'filename(s), either as a list or string')
if self.config_dir is not None:
conf['ignore-from-file'] = [
f if os.path.basename(f) != f
else os.path.join(self.config_dir, f)
for f in conf['ignore-from-file']]
with fileinput.input(conf['ignore-from-file']) as f:
self.ignore = pathspec.PathSpec.from_lines('gitwildmatch', f)
elif 'ignore' in conf:
Expand Down Expand Up @@ -145,10 +154,12 @@ def validate(self):
except Exception as e:
raise YamlLintConfigError(f'invalid config: {e}') from e

self.rules[id] = validate_rule_conf(rule, self.rules[id])
self.rules[id] = validate_rule_conf(rule,
self.rules[id],
self.config_dir)


def validate_rule_conf(rule, conf):
def validate_rule_conf(rule, conf, config_dir=None):
if conf is False: # disable
return False

Expand All @@ -163,6 +174,11 @@ def validate_rule_conf(rule, conf):
raise YamlLintConfigError(
'invalid config: ignore-from-file should contain '
'valid filename(s), either as a list or string')
if config_dir is not None:
conf['ignore-from-file'] = [
f if os.path.basename(f) != f
else os.path.join(config_dir, f)
for f in conf['ignore-from-file']]
with fileinput.input(conf['ignore-from-file']) as f:
conf['ignore'] = pathspec.PathSpec.from_lines(
'gitwildmatch', f)
Expand Down
Loading