summaryrefslogtreecommitdiffstats
path: root/src/ansiblelint/formatters/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/ansiblelint/formatters/__init__.py')
-rw-r--r--src/ansiblelint/formatters/__init__.py61
1 files changed, 52 insertions, 9 deletions
diff --git a/src/ansiblelint/formatters/__init__.py b/src/ansiblelint/formatters/__init__.py
index 9ddca00..187d803 100644
--- a/src/ansiblelint/formatters/__init__.py
+++ b/src/ansiblelint/formatters/__init__.py
@@ -1,4 +1,5 @@
"""Output formatters."""
+
from __future__ import annotations
import hashlib
@@ -14,6 +15,7 @@ from ansiblelint.version import __version__
if TYPE_CHECKING:
from ansiblelint.errors import MatchError
+ from ansiblelint.rules import BaseRule # type: ignore[attr-defined]
T = TypeVar("T", bound="BaseFormatter") # type: ignore[type-arg]
@@ -27,6 +29,7 @@ class BaseFormatter(Generic[T]):
----
base_dir (str|Path): reference directory against which display relative path.
display_relative_path (bool): whether to show path as relative or absolute
+
"""
def __init__(self, base_dir: str | Path, display_relative_path: bool) -> None:
@@ -143,7 +146,7 @@ class CodeclimateJSONFormatter(BaseFormatter[Any]):
"""Format a list of match errors as a JSON string."""
if not isinstance(matches, list):
msg = f"The {self.__class__} was expecting a list of MatchError."
- raise RuntimeError(msg)
+ raise TypeError(msg)
result = []
for match in matches:
@@ -210,7 +213,7 @@ class SarifFormatter(BaseFormatter[Any]):
"""Format a list of match errors as a JSON string."""
if not isinstance(matches, list):
msg = f"The {self.__class__} was expecting a list of MatchError."
- raise RuntimeError(msg)
+ raise TypeError(msg)
root_path = Path(str(self.base_dir)).as_uri()
root_path = root_path + "/" if not root_path.endswith("/") else root_path
@@ -264,7 +267,7 @@ class SarifFormatter(BaseFormatter[Any]):
"text": str(match.message),
},
"defaultConfiguration": {
- "level": self._to_sarif_level(match),
+ "level": self.get_sarif_rule_severity_level(match.rule),
},
"help": {
"text": str(match.rule.description),
@@ -275,12 +278,21 @@ class SarifFormatter(BaseFormatter[Any]):
return rule
def _to_sarif_result(self, match: MatchError) -> dict[str, Any]:
+ # https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/sarif-v2.1.0-errata01-os-complete.html#_Toc141790898
+ if match.level not in ("warning", "error", "note", "none"):
+ msg = "Unexpected failure to map '%s' level to SARIF."
+ raise RuntimeError(
+ msg,
+ match.level,
+ )
+
result: dict[str, Any] = {
"ruleId": match.tag,
+ "level": self.get_sarif_result_severity_level(match),
"message": {
- "text": str(match.details)
- if str(match.details)
- else str(match.message),
+ "text": (
+ str(match.details) if str(match.details) else str(match.message)
+ ),
},
"locations": [
{
@@ -303,6 +315,37 @@ class SarifFormatter(BaseFormatter[Any]):
return result
@staticmethod
- def _to_sarif_level(match: MatchError) -> str:
- # sarif accepts only 4 levels: error, warning, note, none
- return match.level
+ def get_sarif_rule_severity_level(rule: BaseRule) -> str:
+ """General SARIF severity level for a rule.
+
+ Note: Can differ from an actual result/match severity.
+ Possible values: "none", "note", "warning", "error"
+
+ see: https://github.com/oasis-tcs/sarif-spec/blob/123e95847b13fbdd4cbe2120fa5e33355d4a042b/Schemata/sarif-schema-2.1.0.json#L1934-L1939
+ """
+ if rule.severity in ["VERY_HIGH", "HIGH"]:
+ return "error"
+
+ if rule.severity in ["MEDIUM", "LOW", "VERY_LOW"]:
+ return "warning"
+
+ if rule.severity == "INFO":
+ return "note"
+
+ return "none"
+
+ @staticmethod
+ def get_sarif_result_severity_level(match: MatchError) -> str:
+ """SARIF severity level for an actual result/match.
+
+ Possible values: "none", "note", "warning", "error"
+
+ see: https://github.com/oasis-tcs/sarif-spec/blob/123e95847b13fbdd4cbe2120fa5e33355d4a042b/Schemata/sarif-schema-2.1.0.json#L2066-L2071
+ """
+ if not match.level:
+ return "none"
+
+ if match.level in ["warning", "error"]:
+ return match.level
+
+ return "note"