summaryrefslogtreecommitdiffstats
path: root/lib/ansiblelint/formatters
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-14 20:04:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-14 20:04:50 +0000
commit782f8df6e41f29dce2db4970a3ad84aaeb7d8c5f (patch)
tree3a88a542cd8074743d251881131510157cfc510b /lib/ansiblelint/formatters
parentInitial commit. (diff)
downloadansible-lint-782f8df6e41f29dce2db4970a3ad84aaeb7d8c5f.tar.xz
ansible-lint-782f8df6e41f29dce2db4970a3ad84aaeb7d8c5f.zip
Adding upstream version 4.3.7.upstream/4.3.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/ansiblelint/formatters')
-rw-r--r--lib/ansiblelint/formatters/__init__.py167
1 files changed, 167 insertions, 0 deletions
diff --git a/lib/ansiblelint/formatters/__init__.py b/lib/ansiblelint/formatters/__init__.py
new file mode 100644
index 0000000..7395183
--- /dev/null
+++ b/lib/ansiblelint/formatters/__init__.py
@@ -0,0 +1,167 @@
+"""Output formatters."""
+import os
+from pathlib import Path
+from typing import TYPE_CHECKING, Generic, TypeVar, Union
+
+from ansiblelint.color import Color, colorize
+
+if TYPE_CHECKING:
+ from ansiblelint.errors import MatchError
+
+T = TypeVar('T', bound='BaseFormatter')
+
+
+class BaseFormatter(Generic[T]):
+ """Formatter of ansible-lint output.
+
+ Base class for output formatters.
+
+ Args:
+ 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: Union[str, Path], display_relative_path: bool) -> None:
+ """Initialize a BaseFormatter instance."""
+ if isinstance(base_dir, str):
+ base_dir = Path(base_dir)
+ if base_dir: # can be None
+ base_dir = base_dir.absolute()
+
+ # Required 'cause os.path.relpath() does not accept Path before 3.6
+ if isinstance(base_dir, Path):
+ base_dir = str(base_dir) # Drop when Python 3.5 is no longer supported
+
+ self._base_dir = base_dir if display_relative_path else None
+
+ def _format_path(self, path: Union[str, Path]) -> str:
+ # Required 'cause os.path.relpath() does not accept Path before 3.6
+ if isinstance(path, Path):
+ path = str(path) # Drop when Python 3.5 is no longer supported
+
+ if not self._base_dir:
+ return path
+ # Use os.path.relpath 'cause Path.relative_to() misbehaves
+ return os.path.relpath(path, start=self._base_dir)
+
+ def format(self, match: "MatchError", colored: bool = False) -> str:
+ return str(match)
+
+
+class Formatter(BaseFormatter):
+
+ def format(self, match: "MatchError", colored: bool = False) -> str:
+ formatstr = u"{0} {1}\n{2}:{3}\n{4}\n"
+ _id = getattr(match.rule, 'id', '000')
+ if colored:
+ return formatstr.format(
+ colorize(u"[{0}]".format(_id), Color.error_code),
+ colorize(match.message, Color.error_title),
+ colorize(self._format_path(match.filename or ""), Color.filename),
+ colorize(str(match.linenumber), Color.linenumber),
+ colorize(u"{0}".format(match.details), Color.line))
+ else:
+ return formatstr.format(_id,
+ match.message,
+ match.filename or "",
+ match.linenumber,
+ match.details)
+
+
+class QuietFormatter(BaseFormatter):
+
+ def format(self, match: "MatchError", colored: bool = False) -> str:
+ formatstr = u"{0} {1}:{2}"
+ if colored:
+ return formatstr.format(
+ colorize(u"[{0}]".format(match.rule.id), Color.error_code),
+ colorize(self._format_path(match.filename or ""), Color.filename),
+ colorize(str(match.linenumber), Color.linenumber))
+ else:
+ return formatstr.format(match.rule.id, self._format_path(match.filename or ""),
+ match.linenumber)
+
+
+class ParseableFormatter(BaseFormatter):
+
+ def format(self, match: "MatchError", colored: bool = False) -> str:
+ formatstr = u"{0}:{1}: [{2}] {3}"
+ if colored:
+ return formatstr.format(
+ colorize(self._format_path(match.filename or ""), Color.filename),
+ colorize(str(match.linenumber), Color.linenumber),
+ colorize(u"E{0}".format(match.rule.id), Color.error_code),
+ colorize(u"{0}".format(match.message), Color.error_title))
+ else:
+ return formatstr.format(self._format_path(match.filename or ""),
+ match.linenumber,
+ "E" + match.rule.id,
+ match.message)
+
+
+class AnnotationsFormatter(BaseFormatter):
+ # https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message
+ """Formatter for emitting violations as GitHub Workflow Commands.
+
+ These commands trigger the GHA Workflow runners platform to post violations
+ in a form of GitHub Checks API annotations that appear rendered in pull-
+ request files view.
+
+ ::debug file={name},line={line},col={col},severity={severity}::{message}
+ ::warning file={name},line={line},col={col},severity={severity}::{message}
+ ::error file={name},line={line},col={col},severity={severity}::{message}
+
+ Supported levels: debug, warning, error
+ """
+
+ def format(self, match: "MatchError", colored: bool = False) -> str:
+ """Prepare a match instance for reporting as a GitHub Actions annotation."""
+ if colored:
+ raise ValueError('The colored mode is not supported.')
+
+ level = self._severity_to_level(match.rule.severity)
+ file_path = self._format_path(match.filename or "")
+ line_num = match.linenumber
+ rule_id = match.rule.id
+ severity = match.rule.severity
+ violation_details = match.message
+ return (
+ f"::{level} file={file_path},line={line_num},severity={severity}"
+ f"::[E{rule_id}] {violation_details}"
+ )
+
+ @staticmethod
+ def _severity_to_level(severity: str) -> str:
+ if severity in ['VERY_LOW', 'LOW']:
+ return 'warning'
+ elif severity in ['INFO']:
+ return 'debug'
+ # ['MEDIUM', 'HIGH', 'VERY_HIGH'] or anything else
+ return 'error'
+
+
+class ParseableSeverityFormatter(BaseFormatter):
+
+ def format(self, match: "MatchError", colored: bool = False) -> str:
+ formatstr = u"{0}:{1}: [{2}] [{3}] {4}"
+
+ filename = self._format_path(match.filename or "")
+ linenumber = str(match.linenumber)
+ rule_id = u"E{0}".format(match.rule.id)
+ severity = match.rule.severity
+ message = str(match.message)
+
+ if colored:
+ filename = colorize(filename, Color.filename)
+ linenumber = colorize(linenumber, Color.linenumber)
+ rule_id = colorize(rule_id, Color.error_code)
+ severity = colorize(severity, Color.error_code)
+ message = colorize(message, Color.error_title)
+
+ return formatstr.format(
+ filename,
+ linenumber,
+ rule_id,
+ severity,
+ message,
+ )