Skip to content

Add noqa skips in otherwise empty lines to the next non-empty line #4567

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 26 additions & 0 deletions examples/playbooks/vars/noqa_multiline.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
# noqa: jinja[spacing]
foo_postgresql_grafana_password_encoded: >-
{% if '!' in foo_postgresql_grafana_password or '#' in foo_postgresql_grafana_password %}
{{- ('\"\"\"' + foo_postgresql_grafana_password + '\"\"\"') | b64encode -}}
{% else %}
{{- foo_postgresql_grafana_password | b64encode -}}
{% endif %}

# noqa: jinja[spacing]

foo_postgresql_grafana_password_encoded_2: >-
{% if '!' in foo_postgresql_grafana_password or '#' in foo_postgresql_grafana_password %}
{{- ('\"\"\"' + foo_postgresql_grafana_password + '\"\"\"') | b64encode -}}
{% else %}
{{- foo_postgresql_grafana_password | b64encode -}}
{% endif %}

inner:
# noqa: jinja[spacing]
foo_postgresql_grafana_password_encoded: >-
{% if '!' in foo_postgresql_grafana_password or '#' in foo_postgresql_grafana_password %}
{{- ('\"\"\"' + foo_postgresql_grafana_password + '\"\"\"') | b64encode -}}
{% else %}
{{- foo_postgresql_grafana_password | b64encode -}}
{% endif %}
31 changes: 29 additions & 2 deletions src/ansiblelint/skip_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@

_logger = logging.getLogger(__name__)
_found_deprecated_tags: set[str] = set()
_noqa_comment_re = re.compile(r"^# noqa(\s|:)")
_noqa_comment_re = re.compile(r"^\s*# noqa(\s|:)", flags=re.MULTILINE)
_noqa_comment_line_re = re.compile(r"^\s*# noqa(\s|:).*$")

# playbook: Sequence currently expects only instances of one of the two
# classes below but we should consider avoiding this chimera.
Expand Down Expand Up @@ -257,6 +258,25 @@ def get_nested_tasks(task: Any) -> Generator[Any, None, None]:
yield task


def _continue_skip_next_lines(
lintable: Lintable,
) -> None:
"""When a line only contains a noqa comment (and possibly indentation), add the skip also to the next non-empty line."""
# If line starts with _noqa_comment_line_re, add next non-empty line to same lintable.line_skips
line_content = lintable.content.splitlines()
for line_no in list(lintable.line_skips.keys()):
if _noqa_comment_line_re.fullmatch(line_content[line_no - 1]):
# Find next non-empty line
next_line_no = line_no
while next_line_no < len(line_content) and not line_content[next_line_no].strip():
next_line_no += 1
if next_line_no >= len(line_content):
continue
lintable.line_skips[next_line_no + 1].update(
lintable.line_skips[line_no],
)


def _get_rule_skips_from_yaml(
yaml_input: Sequence[Any],
lintable: Lintable,
Expand All @@ -268,7 +288,13 @@ def _get_rule_skips_from_yaml(
return []

def traverse_yaml(obj: Any) -> None:
for entry in obj.ca.items.values():
traversable = list(obj.ca.items.values())
if obj.ca.comment:
traversable.append(obj.ca.comment)
for entry in traversable:
# flatten all lists we might have in entries. Some arcane ruamel CommentedMap magic
entry = [item for sublist in entry if sublist is not None
for item in (sublist if isinstance(sublist, list) else [sublist])]
for v in entry:
if isinstance(v, CommentToken):
comment_str = v.value
Expand Down Expand Up @@ -298,6 +324,7 @@ def traverse_yaml(obj: Any) -> None:
for comment_obj_str in yaml_comment_obj_strings:
for line in comment_obj_str.split(r"\n"):
rule_id_list.extend(get_rule_skips_from_line(line, lintable=lintable))
_continue_skip_next_lines(lintable)

return [normalize_tag(tag) for tag in rule_id_list]

Expand Down
7 changes: 7 additions & 0 deletions test/test_skiputils.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ def test_playbook_noqa2(default_text_runner: RunFromText) -> None:
assert len(results) == 1


def test_var_noqa(default_text_runner: RunFromText) -> None:
"""Check that noqa is properly taken into account on vars and tasks."""
results = default_text_runner.run(Path("examples/playbooks/vars/noqa_multiline.yml"))
# Should raise no error at "SOME_VAR".
assert len(results) == 0


@pytest.mark.parametrize(
("lintable", "yaml", "expected_form"),
(
Expand Down
Loading