|
|
|
@ -1,3 +1,4 @@
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
# Copyright (C) 2016 Adrien Vergé
|
|
|
|
|
#
|
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
@ -13,55 +14,28 @@
|
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
from io import StringIO
|
|
|
|
|
try:
|
|
|
|
|
from cStringIO import StringIO
|
|
|
|
|
except ImportError:
|
|
|
|
|
from io import StringIO
|
|
|
|
|
import fcntl
|
|
|
|
|
import locale
|
|
|
|
|
import os
|
|
|
|
|
import pty
|
|
|
|
|
import shutil
|
|
|
|
|
import sys
|
|
|
|
|
import tempfile
|
|
|
|
|
import unittest
|
|
|
|
|
try:
|
|
|
|
|
assert sys.version_info >= (2, 7)
|
|
|
|
|
import unittest
|
|
|
|
|
except AssertionError:
|
|
|
|
|
import unittest2 as unittest
|
|
|
|
|
|
|
|
|
|
from tests.common import build_temp_workspace, temp_workspace
|
|
|
|
|
from tests.common import build_temp_workspace
|
|
|
|
|
|
|
|
|
|
from yamllint import cli
|
|
|
|
|
from yamllint import config
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class RunContext:
|
|
|
|
|
"""Context manager for ``cli.run()`` to capture exit code and streams."""
|
|
|
|
|
|
|
|
|
|
def __init__(self, case):
|
|
|
|
|
self.stdout = self.stderr = None
|
|
|
|
|
self._raises_ctx = case.assertRaises(SystemExit)
|
|
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
|
self._raises_ctx.__enter__()
|
|
|
|
|
sys.stdout = self.outstream = StringIO()
|
|
|
|
|
sys.stderr = self.errstream = StringIO()
|
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
def __exit__(self, *exc_info):
|
|
|
|
|
self.stdout, sys.stdout = self.outstream.getvalue(), sys.__stdout__
|
|
|
|
|
self.stderr, sys.stderr = self.errstream.getvalue(), sys.__stderr__
|
|
|
|
|
return self._raises_ctx.__exit__(*exc_info)
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def returncode(self):
|
|
|
|
|
return self._raises_ctx.exception.code
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Check system's UTF-8 availability
|
|
|
|
|
def utf8_available():
|
|
|
|
|
try:
|
|
|
|
|
locale.setlocale(locale.LC_ALL, 'C.UTF-8')
|
|
|
|
|
locale.setlocale(locale.LC_ALL, (None, None))
|
|
|
|
|
return True
|
|
|
|
|
except locale.Error: # pragma: no cover
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(sys.version_info < (2, 7), 'Python 2.6 not supported')
|
|
|
|
|
class CommandLineTestCase(unittest.TestCase):
|
|
|
|
|
@classmethod
|
|
|
|
|
def setUpClass(cls):
|
|
|
|
@ -79,9 +53,6 @@ class CommandLineTestCase(unittest.TestCase):
|
|
|
|
|
# file in dir
|
|
|
|
|
'sub/ok.yaml': '---\n'
|
|
|
|
|
'key: value\n',
|
|
|
|
|
# directory that looks like a yaml file
|
|
|
|
|
'sub/directory.yaml/not-yaml.txt': '',
|
|
|
|
|
'sub/directory.yaml/empty.yml': '',
|
|
|
|
|
# file in very nested dir
|
|
|
|
|
's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml': '---\n'
|
|
|
|
|
'key: value\n'
|
|
|
|
@ -92,22 +63,12 @@ class CommandLineTestCase(unittest.TestCase):
|
|
|
|
|
'no-yaml.json': '---\n'
|
|
|
|
|
'key: value\n',
|
|
|
|
|
# non-ASCII chars
|
|
|
|
|
'non-ascii/éçäγλνπ¥/utf-8': (
|
|
|
|
|
'---\n'
|
|
|
|
|
'- hétérogénéité\n'
|
|
|
|
|
'# 19.99 €\n'
|
|
|
|
|
'- お早う御座います。\n'
|
|
|
|
|
'# الأَبْجَدِيَّة العَرَبِيَّة\n').encode('utf-8'),
|
|
|
|
|
# dos line endings yaml
|
|
|
|
|
'dos.yml': '---\r\n'
|
|
|
|
|
'dos: true',
|
|
|
|
|
# different key-ordering by locale
|
|
|
|
|
'c.yaml': '---\n'
|
|
|
|
|
'A: true\n'
|
|
|
|
|
'a: true',
|
|
|
|
|
'en.yaml': '---\n'
|
|
|
|
|
'a: true\n'
|
|
|
|
|
'A: true'
|
|
|
|
|
'non-ascii/utf-8': (
|
|
|
|
|
u'---\n'
|
|
|
|
|
u'- hétérogénéité\n'
|
|
|
|
|
u'# 19.99 €\n'
|
|
|
|
|
u'- お早う御座います。\n'
|
|
|
|
|
u'# الأَبْجَدِيَّة العَرَبِيَّة\n').encode('utf-8'),
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
@ -116,19 +77,12 @@ class CommandLineTestCase(unittest.TestCase):
|
|
|
|
|
|
|
|
|
|
shutil.rmtree(cls.wd)
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(not utf8_available() and sys.version_info < (3, 7),
|
|
|
|
|
'UTF-8 paths not supported')
|
|
|
|
|
def test_find_files_recursively(self):
|
|
|
|
|
conf = config.YamlLintConfig('extends: default')
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(cli.find_files_recursively([self.wd], conf)),
|
|
|
|
|
sorted(cli.find_files_recursively([self.wd])),
|
|
|
|
|
[os.path.join(self.wd, 'a.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'c.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'dos.yml'),
|
|
|
|
|
os.path.join(self.wd, 'empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 'en.yaml'),
|
|
|
|
|
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/directory.yaml/empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/ok.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'warn.yaml')],
|
|
|
|
|
)
|
|
|
|
@ -136,14 +90,14 @@ class CommandLineTestCase(unittest.TestCase):
|
|
|
|
|
items = [os.path.join(self.wd, 'sub/ok.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'empty-dir')]
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(cli.find_files_recursively(items, conf)),
|
|
|
|
|
sorted(cli.find_files_recursively(items)),
|
|
|
|
|
[os.path.join(self.wd, 'sub/ok.yaml')],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
items = [os.path.join(self.wd, 'empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 's')]
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(cli.find_files_recursively(items, conf)),
|
|
|
|
|
sorted(cli.find_files_recursively(items)),
|
|
|
|
|
[os.path.join(self.wd, 'empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml')],
|
|
|
|
|
)
|
|
|
|
@ -151,356 +105,261 @@ class CommandLineTestCase(unittest.TestCase):
|
|
|
|
|
items = [os.path.join(self.wd, 'sub'),
|
|
|
|
|
os.path.join(self.wd, '/etc/another/file')]
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(cli.find_files_recursively(items, conf)),
|
|
|
|
|
sorted(cli.find_files_recursively(items)),
|
|
|
|
|
[os.path.join(self.wd, '/etc/another/file'),
|
|
|
|
|
os.path.join(self.wd, 'sub/directory.yaml/empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/ok.yaml')],
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
conf = config.YamlLintConfig('extends: default\n'
|
|
|
|
|
'yaml-files:\n'
|
|
|
|
|
' - \'*.yaml\' \n')
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(cli.find_files_recursively([self.wd], conf)),
|
|
|
|
|
[os.path.join(self.wd, 'a.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'c.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'en.yaml'),
|
|
|
|
|
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/ok.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'warn.yaml')]
|
|
|
|
|
)
|
|
|
|
|
def test_run_with_bad_arguments(self):
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(())
|
|
|
|
|
|
|
|
|
|
conf = config.YamlLintConfig('extends: default\n'
|
|
|
|
|
'yaml-files:\n'
|
|
|
|
|
' - \'*.yml\'\n')
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(cli.find_files_recursively([self.wd], conf)),
|
|
|
|
|
[os.path.join(self.wd, 'dos.yml'),
|
|
|
|
|
os.path.join(self.wd, 'empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/directory.yaml/empty.yml')]
|
|
|
|
|
)
|
|
|
|
|
self.assertNotEqual(ctx.exception.code, 0)
|
|
|
|
|
|
|
|
|
|
conf = config.YamlLintConfig('extends: default\n'
|
|
|
|
|
'yaml-files:\n'
|
|
|
|
|
' - \'*.json\'\n')
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(cli.find_files_recursively([self.wd], conf)),
|
|
|
|
|
[os.path.join(self.wd, 'no-yaml.json')]
|
|
|
|
|
)
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, '')
|
|
|
|
|
self.assertRegexpMatches(err, r'^usage')
|
|
|
|
|
|
|
|
|
|
conf = config.YamlLintConfig('extends: default\n'
|
|
|
|
|
'yaml-files:\n'
|
|
|
|
|
' - \'*\'\n')
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(cli.find_files_recursively([self.wd], conf)),
|
|
|
|
|
[os.path.join(self.wd, 'a.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'c.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'dos.yml'),
|
|
|
|
|
os.path.join(self.wd, 'empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 'en.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'no-yaml.json'),
|
|
|
|
|
os.path.join(self.wd, 'non-ascii/éçäγλνπ¥/utf-8'),
|
|
|
|
|
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/directory.yaml/empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/directory.yaml/not-yaml.txt'),
|
|
|
|
|
os.path.join(self.wd, 'sub/ok.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'warn.yaml')]
|
|
|
|
|
)
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('--unknown-arg', ))
|
|
|
|
|
|
|
|
|
|
conf = config.YamlLintConfig('extends: default\n'
|
|
|
|
|
'yaml-files:\n'
|
|
|
|
|
' - \'*.yaml\'\n'
|
|
|
|
|
' - \'*\'\n'
|
|
|
|
|
' - \'**\'\n')
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(cli.find_files_recursively([self.wd], conf)),
|
|
|
|
|
[os.path.join(self.wd, 'a.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'c.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'dos.yml'),
|
|
|
|
|
os.path.join(self.wd, 'empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 'en.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'no-yaml.json'),
|
|
|
|
|
os.path.join(self.wd, 'non-ascii/éçäγλνπ¥/utf-8'),
|
|
|
|
|
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/directory.yaml/empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/directory.yaml/not-yaml.txt'),
|
|
|
|
|
os.path.join(self.wd, 'sub/ok.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'warn.yaml')]
|
|
|
|
|
)
|
|
|
|
|
self.assertNotEqual(ctx.exception.code, 0)
|
|
|
|
|
|
|
|
|
|
conf = config.YamlLintConfig('extends: default\n'
|
|
|
|
|
'yaml-files:\n'
|
|
|
|
|
' - \'s/**\'\n'
|
|
|
|
|
' - \'**/utf-8\'\n')
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(cli.find_files_recursively([self.wd], conf)),
|
|
|
|
|
[os.path.join(self.wd, 'non-ascii/éçäγλνπ¥/utf-8')]
|
|
|
|
|
)
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, '')
|
|
|
|
|
self.assertRegexpMatches(err, r'^usage')
|
|
|
|
|
|
|
|
|
|
def test_run_with_bad_arguments(self):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(())
|
|
|
|
|
self.assertNotEqual(ctx.returncode, 0)
|
|
|
|
|
self.assertEqual(ctx.stdout, '')
|
|
|
|
|
self.assertRegex(ctx.stderr, r'^usage')
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-c', './conf.yaml', '-d', 'relaxed', 'file'))
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('--unknown-arg', ))
|
|
|
|
|
self.assertNotEqual(ctx.returncode, 0)
|
|
|
|
|
self.assertEqual(ctx.stdout, '')
|
|
|
|
|
self.assertRegex(ctx.stderr, r'^usage')
|
|
|
|
|
self.assertNotEqual(ctx.exception.code, 0)
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-c', './conf.yaml', '-d', 'relaxed', 'file'))
|
|
|
|
|
self.assertNotEqual(ctx.returncode, 0)
|
|
|
|
|
self.assertEqual(ctx.stdout, '')
|
|
|
|
|
self.assertRegex(
|
|
|
|
|
ctx.stderr.splitlines()[-1],
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, '')
|
|
|
|
|
self.assertRegexpMatches(
|
|
|
|
|
err.splitlines()[-1],
|
|
|
|
|
r'^yamllint: error: argument -d\/--config-data: '
|
|
|
|
|
r'not allowed with argument -c\/--config-file$'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# checks if reading from stdin and files are mutually exclusive
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-', 'file'))
|
|
|
|
|
self.assertNotEqual(ctx.returncode, 0)
|
|
|
|
|
self.assertEqual(ctx.stdout, '')
|
|
|
|
|
self.assertRegex(ctx.stderr, r'^usage')
|
|
|
|
|
|
|
|
|
|
def test_run_with_bad_config(self):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-d', 'rules: {a: b}', 'file'))
|
|
|
|
|
self.assertEqual(ctx.returncode, -1)
|
|
|
|
|
self.assertEqual(ctx.stdout, '')
|
|
|
|
|
self.assertRegex(ctx.stderr, r'^invalid config: no such rule')
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, -1)
|
|
|
|
|
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, '')
|
|
|
|
|
self.assertRegexpMatches(err, r'^invalid config: no such rule')
|
|
|
|
|
|
|
|
|
|
def test_run_with_empty_config(self):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-d', '', 'file'))
|
|
|
|
|
self.assertEqual(ctx.returncode, -1)
|
|
|
|
|
self.assertEqual(ctx.stdout, '')
|
|
|
|
|
self.assertRegex(ctx.stderr, r'^invalid config: not a dict')
|
|
|
|
|
|
|
|
|
|
def test_run_with_implicit_extends_config(self):
|
|
|
|
|
path = os.path.join(self.wd, 'warn.yaml')
|
|
|
|
|
self.assertEqual(ctx.exception.code, -1)
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-d', 'default', '-f', 'parsable', path))
|
|
|
|
|
expected_out = ('%s:1:1: [warning] missing document start "---" '
|
|
|
|
|
'(document-start)\n' % path)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
(ctx.returncode, ctx.stdout, ctx.stderr), (0, expected_out, ''))
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, '')
|
|
|
|
|
self.assertRegexpMatches(err, r'^invalid config: not a dict')
|
|
|
|
|
|
|
|
|
|
def test_run_with_config_file(self):
|
|
|
|
|
with open(os.path.join(self.wd, 'config'), 'w') as f:
|
|
|
|
|
f.write('rules: {trailing-spaces: disable}')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-c', f.name, os.path.join(self.wd, 'a.yaml')))
|
|
|
|
|
self.assertEqual(ctx.returncode, 0)
|
|
|
|
|
self.assertEqual(ctx.exception.code, 0)
|
|
|
|
|
|
|
|
|
|
with open(os.path.join(self.wd, 'config'), 'w') as f:
|
|
|
|
|
f.write('rules: {trailing-spaces: enable}')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-c', f.name, os.path.join(self.wd, 'a.yaml')))
|
|
|
|
|
self.assertEqual(ctx.returncode, 1)
|
|
|
|
|
self.assertEqual(ctx.exception.code, 1)
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(os.environ.get('GITHUB_RUN_ID'), '$HOME not overridable')
|
|
|
|
|
def test_run_with_user_global_config_file(self):
|
|
|
|
|
home = os.path.join(self.wd, 'fake-home')
|
|
|
|
|
dir = os.path.join(home, '.config', 'yamllint')
|
|
|
|
|
os.makedirs(dir)
|
|
|
|
|
os.mkdir(home)
|
|
|
|
|
dir = os.path.join(home, '.config')
|
|
|
|
|
os.mkdir(dir)
|
|
|
|
|
dir = os.path.join(dir, 'yamllint')
|
|
|
|
|
os.mkdir(dir)
|
|
|
|
|
config = os.path.join(dir, 'config')
|
|
|
|
|
|
|
|
|
|
self.addCleanup(os.environ.update, HOME=os.environ['HOME'])
|
|
|
|
|
temp = os.environ['HOME']
|
|
|
|
|
os.environ['HOME'] = home
|
|
|
|
|
|
|
|
|
|
with open(config, 'w') as f:
|
|
|
|
|
f.write('rules: {trailing-spaces: disable}')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run((os.path.join(self.wd, 'a.yaml'), ))
|
|
|
|
|
self.assertEqual(ctx.returncode, 0)
|
|
|
|
|
self.assertEqual(ctx.exception.code, 0)
|
|
|
|
|
|
|
|
|
|
with open(config, 'w') as f:
|
|
|
|
|
f.write('rules: {trailing-spaces: enable}')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run((os.path.join(self.wd, 'a.yaml'), ))
|
|
|
|
|
self.assertEqual(ctx.returncode, 1)
|
|
|
|
|
self.assertEqual(ctx.exception.code, 1)
|
|
|
|
|
|
|
|
|
|
def test_run_with_user_xdg_config_home_in_env(self):
|
|
|
|
|
self.addCleanup(os.environ.__delitem__, 'XDG_CONFIG_HOME')
|
|
|
|
|
os.environ['HOME'] = temp
|
|
|
|
|
|
|
|
|
|
with tempfile.TemporaryDirectory('w') as d:
|
|
|
|
|
os.environ['XDG_CONFIG_HOME'] = d
|
|
|
|
|
os.makedirs(os.path.join(d, 'yamllint'))
|
|
|
|
|
with open(os.path.join(d, 'yamllint', 'config'), 'w') as f:
|
|
|
|
|
f.write('extends: relaxed')
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', os.path.join(self.wd, 'warn.yaml')))
|
|
|
|
|
def test_run_version(self):
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('--version', ))
|
|
|
|
|
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', ''))
|
|
|
|
|
self.assertEqual(ctx.exception.code, 0)
|
|
|
|
|
|
|
|
|
|
def test_run_with_user_yamllint_config_file_in_env(self):
|
|
|
|
|
self.addCleanup(os.environ.__delitem__, 'YAMLLINT_CONFIG_FILE')
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertRegexpMatches(out + err, r'yamllint \d+\.\d+')
|
|
|
|
|
|
|
|
|
|
with tempfile.NamedTemporaryFile('w') as f:
|
|
|
|
|
os.environ['YAMLLINT_CONFIG_FILE'] = f.name
|
|
|
|
|
f.write('rules: {trailing-spaces: disable}')
|
|
|
|
|
f.flush()
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((os.path.join(self.wd, 'a.yaml'), ))
|
|
|
|
|
self.assertEqual(ctx.returncode, 0)
|
|
|
|
|
|
|
|
|
|
with tempfile.NamedTemporaryFile('w') as f:
|
|
|
|
|
os.environ['YAMLLINT_CONFIG_FILE'] = f.name
|
|
|
|
|
f.write('rules: {trailing-spaces: enable}')
|
|
|
|
|
f.flush()
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((os.path.join(self.wd, 'a.yaml'), ))
|
|
|
|
|
self.assertEqual(ctx.returncode, 1)
|
|
|
|
|
|
|
|
|
|
def test_run_with_locale(self):
|
|
|
|
|
# check for availability of locale, otherwise skip the test
|
|
|
|
|
# reset to default before running the test,
|
|
|
|
|
# as the first two runs don't use setlocale()
|
|
|
|
|
try:
|
|
|
|
|
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
|
|
|
|
|
except locale.Error: # pragma: no cover
|
|
|
|
|
self.skipTest('locale en_US.UTF-8 not available')
|
|
|
|
|
locale.setlocale(locale.LC_ALL, (None, None))
|
|
|
|
|
|
|
|
|
|
# C + en.yaml should fail
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-d', 'rules: { key-ordering: enable }',
|
|
|
|
|
os.path.join(self.wd, 'en.yaml')))
|
|
|
|
|
self.assertEqual(ctx.returncode, 1)
|
|
|
|
|
|
|
|
|
|
# C + c.yaml should pass
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-d', 'rules: { key-ordering: enable }',
|
|
|
|
|
os.path.join(self.wd, 'c.yaml')))
|
|
|
|
|
self.assertEqual(ctx.returncode, 0)
|
|
|
|
|
|
|
|
|
|
# the next two runs use setlocale() inside,
|
|
|
|
|
# so we need to clean up afterwards
|
|
|
|
|
self.addCleanup(locale.setlocale, locale.LC_ALL, (None, None))
|
|
|
|
|
|
|
|
|
|
# en_US + en.yaml should pass
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-d', 'locale: en_US.UTF-8\n'
|
|
|
|
|
'rules: { key-ordering: enable }',
|
|
|
|
|
os.path.join(self.wd, 'en.yaml')))
|
|
|
|
|
self.assertEqual(ctx.returncode, 0)
|
|
|
|
|
|
|
|
|
|
# en_US + c.yaml should fail
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-d', 'locale: en_US.UTF-8\n'
|
|
|
|
|
'rules: { key-ordering: enable }',
|
|
|
|
|
os.path.join(self.wd, 'c.yaml')))
|
|
|
|
|
self.assertEqual(ctx.returncode, 1)
|
|
|
|
|
def test_run_non_existing_file(self):
|
|
|
|
|
file = os.path.join(self.wd, 'i-do-not-exist.yaml')
|
|
|
|
|
|
|
|
|
|
def test_run_version(self):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('--version', ))
|
|
|
|
|
self.assertEqual(ctx.returncode, 0)
|
|
|
|
|
self.assertRegex(ctx.stdout + ctx.stderr, r'yamllint \d+\.\d+')
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', file))
|
|
|
|
|
|
|
|
|
|
def test_run_non_existing_file(self):
|
|
|
|
|
path = os.path.join(self.wd, 'i-do-not-exist.yaml')
|
|
|
|
|
self.assertEqual(ctx.exception.code, -1)
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', path))
|
|
|
|
|
self.assertEqual(ctx.returncode, -1)
|
|
|
|
|
self.assertEqual(ctx.stdout, '')
|
|
|
|
|
self.assertRegex(ctx.stderr, r'No such file or directory')
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, '')
|
|
|
|
|
self.assertRegexpMatches(err, r'No such file or directory')
|
|
|
|
|
|
|
|
|
|
def test_run_one_problem_file(self):
|
|
|
|
|
path = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
file = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', path))
|
|
|
|
|
self.assertEqual(ctx.returncode, 1)
|
|
|
|
|
self.assertEqual(ctx.stdout, (
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', file))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, 1)
|
|
|
|
|
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, (
|
|
|
|
|
'%s:2:4: [error] trailing spaces (trailing-spaces)\n'
|
|
|
|
|
'%s:3:4: [error] no new line character at the end of file '
|
|
|
|
|
'(new-line-at-end-of-file)\n' % (path, path)))
|
|
|
|
|
self.assertEqual(ctx.stderr, '')
|
|
|
|
|
'(new-line-at-end-of-file)\n') % (file, file))
|
|
|
|
|
self.assertEqual(err, '')
|
|
|
|
|
|
|
|
|
|
def test_run_one_warning(self):
|
|
|
|
|
path = os.path.join(self.wd, 'warn.yaml')
|
|
|
|
|
file = os.path.join(self.wd, 'warn.yaml')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', path))
|
|
|
|
|
self.assertEqual(ctx.returncode, 0)
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', file))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, 0)
|
|
|
|
|
|
|
|
|
|
def test_run_warning_in_strict_mode(self):
|
|
|
|
|
path = os.path.join(self.wd, 'warn.yaml')
|
|
|
|
|
file = os.path.join(self.wd, 'warn.yaml')
|
|
|
|
|
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', '--strict', file))
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', '--strict', path))
|
|
|
|
|
self.assertEqual(ctx.returncode, 2)
|
|
|
|
|
self.assertEqual(ctx.exception.code, 2)
|
|
|
|
|
|
|
|
|
|
def test_run_one_ok_file(self):
|
|
|
|
|
path = os.path.join(self.wd, 'sub', 'ok.yaml')
|
|
|
|
|
file = os.path.join(self.wd, 'sub', 'ok.yaml')
|
|
|
|
|
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', file))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, 0)
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', path))
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', ''))
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, '')
|
|
|
|
|
self.assertEqual(err, '')
|
|
|
|
|
|
|
|
|
|
def test_run_empty_file(self):
|
|
|
|
|
path = os.path.join(self.wd, 'empty.yml')
|
|
|
|
|
file = os.path.join(self.wd, 'empty.yml')
|
|
|
|
|
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', file))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, 0)
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', path))
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', ''))
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, '')
|
|
|
|
|
self.assertEqual(err, '')
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(not utf8_available(), 'C.UTF-8 not available')
|
|
|
|
|
def test_run_non_ascii_file(self):
|
|
|
|
|
locale.setlocale(locale.LC_ALL, 'C.UTF-8')
|
|
|
|
|
self.addCleanup(locale.setlocale, locale.LC_ALL, (None, None))
|
|
|
|
|
file = os.path.join(self.wd, 'non-ascii', 'utf-8')
|
|
|
|
|
|
|
|
|
|
# Make sure the default localization conditions on this "system"
|
|
|
|
|
# support UTF-8 encoding.
|
|
|
|
|
loc = locale.getlocale()
|
|
|
|
|
try:
|
|
|
|
|
locale.setlocale(locale.LC_ALL, 'C.UTF-8')
|
|
|
|
|
except locale.Error:
|
|
|
|
|
locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
|
|
|
|
|
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', file))
|
|
|
|
|
|
|
|
|
|
path = os.path.join(self.wd, 'non-ascii', 'éçäγλνπ¥', 'utf-8')
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', path))
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', ''))
|
|
|
|
|
locale.setlocale(locale.LC_ALL, loc)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, 0)
|
|
|
|
|
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, '')
|
|
|
|
|
self.assertEqual(err, '')
|
|
|
|
|
|
|
|
|
|
def test_run_multiple_files(self):
|
|
|
|
|
items = [os.path.join(self.wd, 'empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 's')]
|
|
|
|
|
path = items[1] + '/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'
|
|
|
|
|
file = items[1] + '/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run(['-f', 'parsable'] + items)
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stderr), (1, ''))
|
|
|
|
|
self.assertEqual(ctx.stdout, (
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, 1)
|
|
|
|
|
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, (
|
|
|
|
|
'%s:3:1: [error] duplication of key "key" in mapping '
|
|
|
|
|
'(key-duplicates)\n') % path)
|
|
|
|
|
'(key-duplicates)\n') % file)
|
|
|
|
|
self.assertEqual(err, '')
|
|
|
|
|
|
|
|
|
|
def test_run_piped_output_nocolor(self):
|
|
|
|
|
path = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
file = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((path, ))
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stderr), (1, ''))
|
|
|
|
|
self.assertEqual(ctx.stdout, (
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run((file, ))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, 1)
|
|
|
|
|
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, (
|
|
|
|
|
'%s\n'
|
|
|
|
|
' 2:4 error trailing spaces (trailing-spaces)\n'
|
|
|
|
|
' 3:4 error no new line character at the end of file '
|
|
|
|
|
'(new-line-at-end-of-file)\n'
|
|
|
|
|
'\n' % path))
|
|
|
|
|
'\n' % file))
|
|
|
|
|
self.assertEqual(err, '')
|
|
|
|
|
|
|
|
|
|
def test_run_default_format_output_in_tty(self):
|
|
|
|
|
path = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
file = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
|
|
|
|
|
# Create a pseudo-TTY and redirect stdout to it
|
|
|
|
|
master, slave = pty.openpty()
|
|
|
|
|
sys.stdout = sys.stderr = os.fdopen(slave, 'w')
|
|
|
|
|
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run((path, ))
|
|
|
|
|
cli.run((file, ))
|
|
|
|
|
sys.stdout.flush()
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, 1)
|
|
|
|
@ -523,275 +382,60 @@ class CommandLineTestCase(unittest.TestCase):
|
|
|
|
|
' \033[2m3:4\033[0m \033[31merror\033[0m '
|
|
|
|
|
'no new line character at the end of file '
|
|
|
|
|
'\033[2m(new-line-at-end-of-file)\033[0m\n'
|
|
|
|
|
'\n' % path))
|
|
|
|
|
'\n' % file))
|
|
|
|
|
|
|
|
|
|
def test_run_default_format_output_without_tty(self):
|
|
|
|
|
path = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
file = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run((file, ))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, 1)
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((path, ))
|
|
|
|
|
expected_out = (
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, (
|
|
|
|
|
'%s\n'
|
|
|
|
|
' 2:4 error trailing spaces (trailing-spaces)\n'
|
|
|
|
|
' 3:4 error no new line character at the end of file '
|
|
|
|
|
'(new-line-at-end-of-file)\n'
|
|
|
|
|
'\n' % path)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
|
|
|
|
|
'\n' % file))
|
|
|
|
|
self.assertEqual(err, '')
|
|
|
|
|
|
|
|
|
|
def test_run_auto_output_without_tty_output(self):
|
|
|
|
|
path = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
file = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run((file, '--format', 'auto'))
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((path, '--format', 'auto'))
|
|
|
|
|
expected_out = (
|
|
|
|
|
self.assertEqual(ctx.exception.code, 1)
|
|
|
|
|
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, (
|
|
|
|
|
'%s\n'
|
|
|
|
|
' 2:4 error trailing spaces (trailing-spaces)\n'
|
|
|
|
|
' 3:4 error no new line character at the end of file '
|
|
|
|
|
'(new-line-at-end-of-file)\n'
|
|
|
|
|
'\n' % path)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
|
|
|
|
|
'\n' % file))
|
|
|
|
|
self.assertEqual(err, '')
|
|
|
|
|
|
|
|
|
|
def test_run_format_colored(self):
|
|
|
|
|
path = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
file = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((path, '--format', 'colored'))
|
|
|
|
|
expected_out = (
|
|
|
|
|
sys.stdout, sys.stderr = StringIO(), StringIO()
|
|
|
|
|
with self.assertRaises(SystemExit) as ctx:
|
|
|
|
|
cli.run((file, '--format', 'colored'))
|
|
|
|
|
|
|
|
|
|
self.assertEqual(ctx.exception.code, 1)
|
|
|
|
|
|
|
|
|
|
out, err = sys.stdout.getvalue(), sys.stderr.getvalue()
|
|
|
|
|
self.assertEqual(out, (
|
|
|
|
|
'\033[4m%s\033[0m\n'
|
|
|
|
|
' \033[2m2:4\033[0m \033[31merror\033[0m '
|
|
|
|
|
'trailing spaces \033[2m(trailing-spaces)\033[0m\n'
|
|
|
|
|
' \033[2m3:4\033[0m \033[31merror\033[0m '
|
|
|
|
|
'no new line character at the end of file '
|
|
|
|
|
'\033[2m(new-line-at-end-of-file)\033[0m\n'
|
|
|
|
|
'\n' % path)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
|
|
|
|
|
|
|
|
|
|
def test_run_format_colored_warning(self):
|
|
|
|
|
path = os.path.join(self.wd, 'warn.yaml')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((path, '--format', 'colored'))
|
|
|
|
|
expected_out = (
|
|
|
|
|
'\033[4m%s\033[0m\n'
|
|
|
|
|
' \033[2m1:1\033[0m \033[33mwarning\033[0m '
|
|
|
|
|
'missing document start "---" \033[2m(document-start)\033[0m\n'
|
|
|
|
|
'\n' % path)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
(ctx.returncode, ctx.stdout, ctx.stderr), (0, expected_out, ''))
|
|
|
|
|
|
|
|
|
|
def test_run_format_github(self):
|
|
|
|
|
path = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((path, '--format', 'github'))
|
|
|
|
|
expected_out = (
|
|
|
|
|
'::group::%s\n'
|
|
|
|
|
'::error file=%s,line=2,col=4::2:4 [trailing-spaces] trailing'
|
|
|
|
|
' spaces\n'
|
|
|
|
|
'::error file=%s,line=3,col=4::3:4 [new-line-at-end-of-file] no'
|
|
|
|
|
' new line character at the end of file\n'
|
|
|
|
|
'::endgroup::\n\n'
|
|
|
|
|
% (path, path, path))
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
|
|
|
|
|
|
|
|
|
|
def test_github_actions_detection(self):
|
|
|
|
|
path = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
self.addCleanup(os.environ.__delitem__, 'GITHUB_ACTIONS')
|
|
|
|
|
self.addCleanup(os.environ.__delitem__, 'GITHUB_WORKFLOW')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
os.environ['GITHUB_ACTIONS'] = 'something'
|
|
|
|
|
os.environ['GITHUB_WORKFLOW'] = 'something'
|
|
|
|
|
cli.run((path, ))
|
|
|
|
|
expected_out = (
|
|
|
|
|
'::group::%s\n'
|
|
|
|
|
'::error file=%s,line=2,col=4::2:4 [trailing-spaces] trailing'
|
|
|
|
|
' spaces\n'
|
|
|
|
|
'::error file=%s,line=3,col=4::3:4 [new-line-at-end-of-file] no'
|
|
|
|
|
' new line character at the end of file\n'
|
|
|
|
|
'::endgroup::\n\n'
|
|
|
|
|
% (path, path, path))
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
|
|
|
|
|
|
|
|
|
|
def test_run_read_from_stdin(self):
|
|
|
|
|
# prepares stdin with an invalid yaml string so that we can check
|
|
|
|
|
# for its specific error, and be assured that stdin was read
|
|
|
|
|
self.addCleanup(setattr, sys, 'stdin', sys.__stdin__)
|
|
|
|
|
sys.stdin = StringIO(
|
|
|
|
|
'I am a string\n'
|
|
|
|
|
'therefore: I am an error\n')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-', '-f', 'parsable'))
|
|
|
|
|
expected_out = (
|
|
|
|
|
'stdin:2:10: [error] syntax error: '
|
|
|
|
|
'mapping values are not allowed here (syntax)\n')
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
|
|
|
|
|
|
|
|
|
|
def test_run_no_warnings(self):
|
|
|
|
|
path = os.path.join(self.wd, 'a.yaml')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((path, '--no-warnings', '-f', 'auto'))
|
|
|
|
|
expected_out = (
|
|
|
|
|
'%s\n'
|
|
|
|
|
' 2:4 error trailing spaces (trailing-spaces)\n'
|
|
|
|
|
' 3:4 error no new line character at the end of file '
|
|
|
|
|
'(new-line-at-end-of-file)\n'
|
|
|
|
|
'\n' % path)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
|
|
|
|
|
|
|
|
|
|
path = os.path.join(self.wd, 'warn.yaml')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((path, '--no-warnings', '-f', 'auto'))
|
|
|
|
|
self.assertEqual(ctx.returncode, 0)
|
|
|
|
|
|
|
|
|
|
def test_run_no_warnings_and_strict(self):
|
|
|
|
|
path = os.path.join(self.wd, 'warn.yaml')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run((path, '--no-warnings', '-s'))
|
|
|
|
|
self.assertEqual(ctx.returncode, 2)
|
|
|
|
|
|
|
|
|
|
def test_run_non_universal_newline(self):
|
|
|
|
|
path = os.path.join(self.wd, 'dos.yml')
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-d', 'rules:\n new-lines:\n type: dos', path))
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr), (0, '', ''))
|
|
|
|
|
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-d', 'rules:\n new-lines:\n type: unix', path))
|
|
|
|
|
expected_out = (
|
|
|
|
|
'%s\n'
|
|
|
|
|
' 1:4 error wrong new line character: expected \\n'
|
|
|
|
|
' (new-lines)\n'
|
|
|
|
|
'\n' % path)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
(ctx.returncode, ctx.stdout, ctx.stderr), (1, expected_out, ''))
|
|
|
|
|
|
|
|
|
|
def test_run_list_files(self):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('--list-files', self.wd))
|
|
|
|
|
self.assertEqual(ctx.returncode, 0)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(ctx.stdout.splitlines()),
|
|
|
|
|
[os.path.join(self.wd, 'a.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'c.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'dos.yml'),
|
|
|
|
|
os.path.join(self.wd, 'empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 'en.yaml'),
|
|
|
|
|
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/directory.yaml/empty.yml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/ok.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'warn.yaml')]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
config = '{ignore: "*.yml", yaml-files: ["*.*"]}'
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('--list-files', '-d', config, self.wd))
|
|
|
|
|
self.assertEqual(ctx.returncode, 0)
|
|
|
|
|
self.assertEqual(
|
|
|
|
|
sorted(ctx.stdout.splitlines()),
|
|
|
|
|
[os.path.join(self.wd, 'a.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'c.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'en.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'no-yaml.json'),
|
|
|
|
|
os.path.join(self.wd, 's/s/s/s/s/s/s/s/s/s/s/s/s/s/s/file.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'sub/directory.yaml/not-yaml.txt'),
|
|
|
|
|
os.path.join(self.wd, 'sub/ok.yaml'),
|
|
|
|
|
os.path.join(self.wd, 'warn.yaml')]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CommandLineConfigTestCase(unittest.TestCase):
|
|
|
|
|
def test_config_file(self):
|
|
|
|
|
workspace = {'a.yml': 'hello: world\n'}
|
|
|
|
|
conf = ('---\n'
|
|
|
|
|
'extends: relaxed\n')
|
|
|
|
|
|
|
|
|
|
for conf_file in ('.yamllint', '.yamllint.yml', '.yamllint.yaml'):
|
|
|
|
|
with self.subTest(conf_file):
|
|
|
|
|
with temp_workspace(workspace):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', '.'))
|
|
|
|
|
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr),
|
|
|
|
|
(0, './a.yml:1:1: [warning] missing document '
|
|
|
|
|
'start "---" (document-start)\n', ''))
|
|
|
|
|
|
|
|
|
|
with temp_workspace({**workspace, **{conf_file: conf}}):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
cli.run(('-f', 'parsable', '.'))
|
|
|
|
|
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr),
|
|
|
|
|
(0, '', ''))
|
|
|
|
|
|
|
|
|
|
def test_parent_config_file(self):
|
|
|
|
|
workspace = {'a/b/c/d/e/f/g/a.yml': 'hello: world\n'}
|
|
|
|
|
conf = ('---\n'
|
|
|
|
|
'extends: relaxed\n')
|
|
|
|
|
|
|
|
|
|
for conf_file in ('.yamllint', '.yamllint.yml', '.yamllint.yaml'):
|
|
|
|
|
with self.subTest(conf_file):
|
|
|
|
|
with temp_workspace(workspace):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
os.chdir('a/b/c/d/e/f')
|
|
|
|
|
cli.run(('-f', 'parsable', '.'))
|
|
|
|
|
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr),
|
|
|
|
|
(0, './g/a.yml:1:1: [warning] missing '
|
|
|
|
|
'document start "---" (document-start)\n',
|
|
|
|
|
''))
|
|
|
|
|
|
|
|
|
|
with temp_workspace({**workspace, **{conf_file: conf}}):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
os.chdir('a/b/c/d/e/f')
|
|
|
|
|
cli.run(('-f', 'parsable', '.'))
|
|
|
|
|
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr),
|
|
|
|
|
(0, '', ''))
|
|
|
|
|
|
|
|
|
|
def test_multiple_parent_config_file(self):
|
|
|
|
|
workspace = {'a/b/c/3spaces.yml': 'array:\n'
|
|
|
|
|
' - item\n',
|
|
|
|
|
'a/b/c/4spaces.yml': 'array:\n'
|
|
|
|
|
' - item\n',
|
|
|
|
|
'a/.yamllint': '---\n'
|
|
|
|
|
'extends: relaxed\n'
|
|
|
|
|
'rules:\n'
|
|
|
|
|
' indentation:\n'
|
|
|
|
|
' spaces: 4\n',
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conf3 = ('---\n'
|
|
|
|
|
'extends: relaxed\n'
|
|
|
|
|
'rules:\n'
|
|
|
|
|
' indentation:\n'
|
|
|
|
|
' spaces: 3\n')
|
|
|
|
|
|
|
|
|
|
with temp_workspace(workspace):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
os.chdir('a/b/c')
|
|
|
|
|
cli.run(('-f', 'parsable', '.'))
|
|
|
|
|
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr),
|
|
|
|
|
(0, './3spaces.yml:2:4: [warning] wrong indentation: '
|
|
|
|
|
'expected 4 but found 3 (indentation)\n', ''))
|
|
|
|
|
|
|
|
|
|
with temp_workspace({**workspace, **{'a/b/.yamllint.yml': conf3}}):
|
|
|
|
|
with RunContext(self) as ctx:
|
|
|
|
|
os.chdir('a/b/c')
|
|
|
|
|
cli.run(('-f', 'parsable', '.'))
|
|
|
|
|
|
|
|
|
|
self.assertEqual((ctx.returncode, ctx.stdout, ctx.stderr),
|
|
|
|
|
(0, './4spaces.yml:2:5: [warning] wrong indentation: '
|
|
|
|
|
'expected 3 but found 4 (indentation)\n', ''))
|
|
|
|
|
'\n' % file))
|
|
|
|
|
self.assertEqual(err, '')
|
|
|
|
|