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

JSON & XML formaters #442

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
81951b3
chore: ignore venv
QuentinN42 Feb 3, 2022
b858cbb
refactor: moved formater inside another file
QuentinN42 Feb 3, 2022
3601817
refactor: moved output at the end of the tests
QuentinN42 Feb 3, 2022
46a12a8
fix: missed return statement
QuentinN42 Feb 3, 2022
c4463c7
feat: max_level as separate function
QuentinN42 Feb 3, 2022
6217241
refactor: use object inheritance for the formaters
QuentinN42 Feb 3, 2022
fbf8108
feat: json formater
QuentinN42 Feb 3, 2022
805b9a9
feat: junitxml formater
QuentinN42 Feb 3, 2022
6a06e8d
feat: changed json output file name to path
QuentinN42 Feb 5, 2022
2839489
typo
QuentinN42 Feb 5, 2022
d24519c
feat: add codeclimate output
QuentinN42 Feb 5, 2022
4baaf12
feat: add message to the json format
QuentinN42 Feb 5, 2022
e04f03a
feat: auto infer formats
QuentinN42 Feb 5, 2022
4057451
feat: changed json format according to @adrienverge comment
QuentinN42 Feb 8, 2022
dab7a80
fix: test_run_with_user_global_config_file patched
QuentinN42 Feb 10, 2022
b1ce2f2
test: escape_xml
QuentinN42 Feb 10, 2022
32de447
test: severity_from_level
QuentinN42 Feb 10, 2022
eb48e1d
test: Base class test
QuentinN42 Feb 10, 2022
1f6adf6
test: Class to test all fmt
QuentinN42 Feb 10, 2022
b42ac81
chore: rm coverage
QuentinN42 Feb 10, 2022
d666308
tests: use ddt to parametrize tests
QuentinN42 Feb 10, 2022
4ae5487
feat: add the possibility to pass the level as argument
QuentinN42 Feb 10, 2022
418952c
refactor: match flake requirements
QuentinN42 Feb 10, 2022
48b5e2b
tests: tested formats with errors
QuentinN42 Feb 10, 2022
e018da1
feat: fixed some isues
QuentinN42 Feb 10, 2022
0354c33
ci: add ddt to the tests requirements and update the contributing fil…
QuentinN42 Feb 11, 2022
3561a77
tests: testing skipping warn with None level
QuentinN42 Feb 11, 2022
64e19e8
fix: filter None to exclude them
QuentinN42 Feb 11, 2022
f0000a1
test: test with mixed errors / files
QuentinN42 Feb 11, 2022
fba5b70
tests: use ddt to others classes
QuentinN42 Feb 11, 2022
d7f59fe
test: escape real text
QuentinN42 Feb 11, 2022
ad46f33
test: remaining tests done
QuentinN42 Feb 11, 2022
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ __pycache__
/yamllint.egg-info
/build
/.eggs
.venv
venv
.coverage
3 changes: 3 additions & 0 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,9 @@ def test_run_with_user_global_config_file(self):
config = os.path.join(dir, 'config')

self.addCleanup(os.environ.update, HOME=os.environ['HOME'])
# remove other env vars to make sure we are using the HOME config file.
os.environ.pop('YAMLLINT_CONFIG_FILE', None)
os.environ.pop('XDG_CONFIG_HOME', None)
Comment on lines +308 to +310
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've also patched the test_run_with_user_global_config_file test by adding removing other env vars.

os.environ['HOME'] = home

with open(config, 'w') as f:
Expand Down
128 changes: 13 additions & 115 deletions yamllint/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
import io
import locale
import os
import platform
import sys

from yamllint import APP_DESCRIPTION, APP_NAME, APP_VERSION
from yamllint import linter
from yamllint.config import YamlLintConfig, YamlLintConfigError
from yamllint.linter import PROBLEM_LEVELS
from yamllint.format import show_all_problems, Formater


def find_files_recursively(items, conf):
Expand All @@ -41,110 +41,6 @@ def find_files_recursively(items, conf):
yield item


def supports_color():
supported_platform = not (platform.system() == 'Windows' and not
('ANSICON' in os.environ or
('TERM' in os.environ and
os.environ['TERM'] == 'ANSI')))
return (supported_platform and
hasattr(sys.stdout, 'isatty') and sys.stdout.isatty())


class Format(object):
@staticmethod
def parsable(problem, filename):
return ('%(file)s:%(line)s:%(column)s: [%(level)s] %(message)s' %
{'file': filename,
'line': problem.line,
'column': problem.column,
'level': problem.level,
'message': problem.message})

@staticmethod
def standard(problem, filename):
line = ' %d:%d' % (problem.line, problem.column)
line += max(12 - len(line), 0) * ' '
line += problem.level
line += max(21 - len(line), 0) * ' '
line += problem.desc
if problem.rule:
line += ' (%s)' % problem.rule
return line

@staticmethod
def standard_color(problem, filename):
line = ' \033[2m%d:%d\033[0m' % (problem.line, problem.column)
line += max(20 - len(line), 0) * ' '
if problem.level == 'warning':
line += '\033[33m%s\033[0m' % problem.level
else:
line += '\033[31m%s\033[0m' % problem.level
line += max(38 - len(line), 0) * ' '
line += problem.desc
if problem.rule:
line += ' \033[2m(%s)\033[0m' % problem.rule
return line

@staticmethod
def github(problem, filename):
line = '::'
line += problem.level
line += ' file=' + filename + ','
line += 'line=' + format(problem.line) + ','
line += 'col=' + format(problem.column)
line += '::'
line += format(problem.line)
line += ':'
line += format(problem.column)
line += ' '
if problem.rule:
line += '[' + problem.rule + '] '
line += problem.desc
return line


def show_problems(problems, file, args_format, no_warn):
max_level = 0
first = True

if args_format == 'auto':
if ('GITHUB_ACTIONS' in os.environ and
'GITHUB_WORKFLOW' in os.environ):
args_format = 'github'
elif supports_color():
args_format = 'colored'

for problem in problems:
max_level = max(max_level, PROBLEM_LEVELS[problem.level])
if no_warn and (problem.level != 'error'):
continue
if args_format == 'parsable':
print(Format.parsable(problem, file))
elif args_format == 'github':
if first:
print('::group::%s' % file)
first = False
print(Format.github(problem, file))
elif args_format == 'colored':
if first:
print('\033[4m%s\033[0m' % file)
first = False
print(Format.standard_color(problem, file))
else:
if first:
print(file)
first = False
print(Format.standard(problem, file))

if not first and args_format == 'github':
print('::endgroup::')

if not first and args_format != 'parsable':
print('')

return max_level


def run(argv=None):
parser = argparse.ArgumentParser(prog=APP_NAME,
description=APP_DESCRIPTION)
Expand All @@ -162,8 +58,7 @@ def run(argv=None):
action='store',
help='custom configuration (as YAML source)')
parser.add_argument('-f', '--format',
choices=('parsable', 'standard', 'colored', 'github',
'auto'),
choices=[*Formater.get_formaters_names(), 'auto'],
default='auto', help='format for parsing output')
parser.add_argument('-s', '--strict',
action='store_true',
Expand Down Expand Up @@ -211,7 +106,8 @@ def run(argv=None):
if conf.locale is not None:
locale.setlocale(locale.LC_ALL, conf.locale)

max_level = 0
# problems dict: {file: problems}
all_problems = dict()

for file in find_files_recursively(args.files, conf):
filepath = file[2:] if file.startswith('./') else file
Expand All @@ -221,20 +117,22 @@ def run(argv=None):
except EnvironmentError as e:
print(e, file=sys.stderr)
sys.exit(-1)
prob_level = show_problems(problems, file, args_format=args.format,
no_warn=args.no_warnings)
max_level = max(max_level, prob_level)
all_problems[file] = [pb for pb in problems if pb]

# read yaml from stdin
if args.stdin:
# read yaml from stdin
try:
problems = linter.run(sys.stdin, conf, '')
except EnvironmentError as e:
print(e, file=sys.stderr)
sys.exit(-1)
prob_level = show_problems(problems, 'stdin', args_format=args.format,
no_warn=args.no_warnings)
max_level = max(max_level, prob_level)
all_problems['stdin'] = [pb for pb in problems if pb]

max_level = show_all_problems(
all_problems,
args_format=args.format,
no_warn=args.no_warnings
)

if max_level == PROBLEM_LEVELS['error']:
return_code = 1
Expand Down
Loading