Skip to content

Commit

Permalink
use -f instead of a dedicated argument flag. rewriting TestCodeclimat…
Browse files Browse the repository at this point in the history
…eJSONFormatter unit test. Fix ansible lint issues.
  • Loading branch information
thushjandan committed Feb 6, 2021
1 parent 1b03826 commit 3f038b6
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 34 deletions.
7 changes: 7 additions & 0 deletions docs/usage.rst
Expand Up @@ -91,3 +91,10 @@ are also handled:
:cwd: ..
:returncode: 2
:nostderr:

A codeclimate report in JSON format can be generated with ansible-lint.

.. command-output:: ansible-lint -f codeclimate examples/playbooks/example.yml
:cwd: ..
:returncode: 2
:nostderr:
4 changes: 2 additions & 2 deletions src/ansiblelint/app.py
Expand Up @@ -31,7 +31,7 @@ def render_matches(self, matches: List) -> None:
if isinstance(self.formatter, formatters.CodeclimateJSONFormatter):
# If formatter CodeclimateJSONFormatter is chosen,
# then print only the matches in JSON
console.print(self.formatter.format(matches), markup=False, highlight=False)
console.print(self.formatter.format_result(matches), markup=False, highlight=False)
return None

ignored_matches = [match for match in matches if match.ignored]
Expand Down Expand Up @@ -72,7 +72,7 @@ def choose_formatter_factory(
r = formatters.ParseableFormatter
elif options_list.parseable_severity:
r = formatters.ParseableSeverityFormatter
elif options_list.parseable_codeclimate:
elif options_list.format == 'codeclimate':
r = formatters.CodeclimateJSONFormatter
return r

Expand Down
1 change: 0 additions & 1 deletion src/ansiblelint/cli.py
Expand Up @@ -265,7 +265,6 @@ def merge_config(file_config, cli_config: Namespace) -> Namespace:
bools = (
'display_relative_path',
'parseable',
'parseable_codeclimate',
'parseable_severity',
'quiet',
'use_default_rules',
Expand Down
1 change: 0 additions & 1 deletion src/ansiblelint/config.py
Expand Up @@ -31,7 +31,6 @@
listtags=False,
parseable=False,
parseable_severity=False,
parseable_codeclimate=False,
quiet=False,
rulesdirs=[],
skip_list=[],
Expand Down
9 changes: 6 additions & 3 deletions src/ansiblelint/formatters/__init__.py
Expand Up @@ -150,17 +150,20 @@ def format(self, match: "MatchError") -> str:

class CodeclimateJSONFormatter(BaseFormatter):
"""Formatter for emitting violations in Codeclimate JSON report format.
Reference: https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#data-type
The formatter expects a list of MatchError objects and returns a JSON formatted string.
The spec for the codeclimate report can be found here:
https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#data-type
"""

def format(self, matches: List["MatchError"]) -> str:
def format_result(self, matches: List["MatchError"]) -> str:

if not isinstance(matches, list):
raise RuntimeError("The CodeclimatJSONFormatter was expecting a list of MatchError.")

result = []
for match in matches:
issue = {}
issue: Dict[str, Any] = {}
issue['type'] = 'issue'
issue['check_name'] = f"[{match.rule.id}] {match.message}"
issue['categories'] = match.rule.tags
Expand Down
58 changes: 31 additions & 27 deletions test/TestCodeclimateJSONFormatter.py
@@ -1,37 +1,19 @@
# Copyright (c) 2016 Will Thames <will@thames.id.au>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# pylint: disable=preferred-module # FIXME: remove once migrated per GH-725
import pathlib
import json
import unittest
import pytest

from ansiblelint.errors import MatchError
from ansiblelint.formatters import CodeclimateJSONFormatter
from ansiblelint.rules import AnsibleLintRule


class TestCodeclimateJSONFormatter(unittest.TestCase):
class TestCodeclimateJSONFormatter:

def setUp(self):
@classmethod
def setup_class(self):
self.rule = AnsibleLintRule()
self.rule.id = "TCF0001"
self.rule.severity = "VERY_HIGH"
self.matches = []
self.matches.append(MatchError(
message="message",
Expand All @@ -50,11 +32,33 @@ def setUp(self):
self.formatter = CodeclimateJSONFormatter(pathlib.Path.cwd(), display_relative_path=True)

def test_format_list(self):
self.formatter.format(self.matches)
assert isinstance(self.formatter.format_result(self.matches), str)

def test_result_is_json(self):
json.loads(self.formatter.format(self.matches))
json.loads(self.formatter.format_result(self.matches))

def test_single_match(self):
with self.assertRaises(RuntimeError):
self.formatter.format(self.matches[0])
with pytest.raises(RuntimeError):
self.formatter.format_result(self.matches[0])

def test_result_is_list(self):
result = json.loads(self.formatter.format_result(self.matches))
assert len(result) == 2

def test_validate_codeclimate_schema(self):
result = json.loads(self.formatter.format_result(self.matches))
single_match = result[0]
assert 'type' in single_match
assert single_match['type'] == 'issue'
assert 'check_name' in single_match
assert 'categories' in single_match
assert isinstance(single_match['categories'], list)
assert 'severity' in single_match
assert single_match['severity'] == 'blocker'
assert 'description' in single_match
assert 'fingerprint' in single_match
assert 'location' in single_match
assert 'path' in single_match['location']
assert single_match['location']['path'] == self.matches[0].filename
assert 'lines' in single_match['location']
assert single_match['location']['lines']['begin'] == self.matches[0].linenumber

0 comments on commit 3f038b6

Please sign in to comment.