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

Adjustable whitelines feature #244

Merged
merged 6 commits into from
May 26, 2023
Merged
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
17 changes: 17 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,23 @@ export YAMLFIX_COMMENTS_REQUIRE_STARTING_SPACE="true"

This option enforces a space between the comment indicator (`#`) and the first character in the comment. It implements the enforcement of the yamllint rule `rules.comments.require-starting-space` - see: https://yamllint.readthedocs.io/en/stable/rules.html#module-yamllint.rules.comments

### Whitelines Adjusting

Default: `whitelines: int = 0`<br>
Environment variable override:
```bash
export YAMLFIX_WHITELINES="0"
```

This option allows to keep a speficied number of whitelines between lines.

It's useful if, for one, you like to separate GitHub Actions job steps or Docker-Compose
service definitions with a blank line.

Bear in mind that, like **Comments Whitelines**, it won't insert whitelines if there's no
whitelines in the first place. It will only fix 1 or more whitelines to the desired
amount (or remove them completely by default).

### Comments Whitelines

Default: `comments_whitelines: int = 1`<br>
Expand Down
46 changes: 19 additions & 27 deletions src/yamlfix/adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,9 +353,9 @@ def fix(self, source_code: str) -> str:
self._restore_jinja_variables,
self._restore_double_exclamations,
self._fix_comments,
self._fix_flow_style_lists,
self._fix_whitelines,
self._fix_top_level_lists,
self._fix_flow_style_lists,
self._add_newline_at_end_of_file,
]

Expand Down Expand Up @@ -478,7 +478,7 @@ def _fix_flow_style_lists(source_code: str) -> str:
```

This function moves the closing bracket to the end of the flow-style
list definition.
list definition and positions the newlines after the closing bracket.

Args:
source_code: Source code to be corrected.
Expand All @@ -487,26 +487,9 @@ def _fix_flow_style_lists(source_code: str) -> str:
Corrected source code.
"""
log.debug("Fixing flow-style lists...")
source_lines = source_code.splitlines()
reversed_fixed_source_lines: List[str] = []

should_append_square_brackets: bool = False
for line in reversed(source_lines):
if line == "]":
should_append_square_brackets = True
continue

if line == "":
reversed_fixed_source_lines.append(line)
continue

if should_append_square_brackets:
should_append_square_brackets = False
reversed_fixed_source_lines.append(line + "]")
else:
reversed_fixed_source_lines.append(line)

return "\n".join(reversed(reversed_fixed_source_lines))
pattern = r"\[(?P<items>.*)(?P<newlines>\n+)]"
replacement = r"[\g<items>]\g<newlines>"
return re.sub(pattern, repl=replacement, string=source_code)

@staticmethod
def _fix_truthy_strings(source_code: str) -> str:
Expand Down Expand Up @@ -616,8 +599,8 @@ def _fix_whitelines(self, source_code: str) -> str:
- 0 whiteline is allowed
- Exactly `self.config.comments_whitelines` whitelines are allowed

This method removes extraneous whitelines that are not immediately followed by
a comment.
This method also adjusts amount of whitelines that are not immediately followed
by a comment.

Args:
self: Source code to be corrected.
Expand All @@ -626,20 +609,21 @@ def _fix_whitelines(self, source_code: str) -> str:
Source code with appropriate whitelines standards.
"""
config = self.config
n_whitelines = config.whitelines
n_whitelines_from_content = config.comments_whitelines

re_whitelines_with_comments = "\n\n+[\t ]{0,}[#]"
re_whitelines_with_no_comments = "\n\n+[\t ]{0,}[^#\n\t ]"

remove_whitelines = partial(self._replace_whitelines, n_whitelines=0)
adjust_whitelines = partial(self._replace_whitelines, n_whitelines=n_whitelines)
replace_by_n_whitelines = partial(
self._replace_whitelines,
n_whitelines=n_whitelines_from_content,
)

source_code = re.sub(
pattern=re_whitelines_with_no_comments,
repl=remove_whitelines,
repl=adjust_whitelines,
string=source_code,
)
source_code = self._fix_section_whitelines(source_code)
Expand Down Expand Up @@ -722,7 +706,15 @@ def _restore_double_exclamations(source_code: str) -> str:

@staticmethod
def _add_newline_at_end_of_file(source_code: str) -> str:
return source_code + "\n"
"""Ensures that the file ends with exactly one newline.

Args:
source_code: Source code to be corrected.

Returns:
Corrected source code.
"""
return source_code.rstrip() + "\n"

@staticmethod
def _fix_jinja_variables(source_code: str) -> str:
Expand Down
1 change: 1 addition & 0 deletions src/yamlfix/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class YamlfixConfig(ConfigSchema):
comments_min_spaces_from_content: int = 2
comments_require_starting_space: bool = True
comments_whitelines: int = 1
whitelines: int = 0
section_whitelines: int = 0
config_path: Optional[str] = None
explicit_start: bool = True
Expand Down
109 changes: 109 additions & 0 deletions tests/unit/test_adapter_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -830,3 +830,112 @@ def test_section_whitelines_begin_no_explicit_start(self) -> None:
result = fix_code(source, config)

assert result == fixed_source

def test_whitelines_collapsed(self) -> None:
"""Checks that whitelines are collapsed by default."""
source = dedent(
"""\
key: value

dict:
key: value
nested_dict:
- key: value
key2: value2

- key: value
"""
)
fixed_source = dedent(
"""\
---
key: value
dict:
key: value
nested_dict:
- key: value
key2: value2
- key: value
"""
)
config = YamlfixConfig()

result = fix_code(source, config)

assert result == fixed_source

def test_whitelines_adjusted_to_value(self) -> None:
"""Checks that amount of whitelines are in line with the config value."""
source = dedent(
"""\
key: value

dict:
key: value


nested_list:
- key: value
key2: value2

- key: value
"""
)
fixed_source = dedent(
"""\
---
key: value
dict:
key: value

nested_list:
- key: value
key2: value2

- key: value
"""
)
config = YamlfixConfig()
config.whitelines = 1

result = fix_code(source, config)

assert result == fixed_source

def test_enforcing_flow_style_together_with_adjustable_newlines(self) -> None:
"""Checks that transforming block style sequences to flow style together with
newlines adjusting produces correct result.
"""
source = dedent(
"""\
---
dict:
nested_dict:
key: value
key2:
- list_item


nested_dict2:
key: value
"""
)
fixed_source = dedent(
"""\
---
dict:
nested_dict:
key: value
key2: [list_item]

nested_dict2:
key: value
"""
)
config = YamlfixConfig()
config.whitelines = 1
config.sequence_style = YamlNodeStyle.FLOW_STYLE

result = fix_code(source, config)

assert result == fixed_source
6 changes: 3 additions & 3 deletions tests/unit/test_services.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ def test_fix_code_functions_emit_debug_logs(

fix_code("") # act

expected_logs = [
expected_logs = {
"Setting up ruamel yaml 'quote simple values' configuration...",
"Setting up ruamel yaml 'sequence flow style' configuration...",
"Running ruamel yaml base configuration...",
Expand All @@ -483,8 +483,8 @@ def test_fix_code_functions_emit_debug_logs(
"Fixing comments...",
"Fixing top level lists...",
"Fixing flow-style lists...",
]
assert caplog.messages == expected_logs
}
assert set(caplog.messages) == expected_logs
for record in caplog.records:
assert record.levelname == "DEBUG"

Expand Down