diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 85d1f7df68..bb00bb662f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -50,10 +50,14 @@ repos: rev: v4.1.0 hooks: - id: end-of-file-fixer + # ignore formatting-prettier to have an accurate prettier comparison + # also temporarily ignore formatting-after until #1927 is merged exclude: > (?x)^( test/eco/.*.result| - test/fixtures/formatting-before/.* + test/fixtures/formatting-before/.*| + test/fixtures/formatting-prettier/.*| + test/fixtures/formatting-after/.* )$ - id: trailing-whitespace exclude: > diff --git a/pytest.ini b/pytest.ini index 9177cc2218..5a70560d1a 100644 --- a/pytest.ini +++ b/pytest.ini @@ -64,3 +64,4 @@ xfail_strict = true markers = eco: Tests effects on a set of 3rd party ansible repositories + formatting_fixtures: Test that regenerates and tests formatting fixtures (requires prettier on PATH) diff --git a/test/conftest.py b/test/conftest.py index 784c1edc0f..e18df58e81 100644 --- a/test/conftest.py +++ b/test/conftest.py @@ -1,6 +1,15 @@ import os from contextlib import contextmanager -from typing import Iterator +from typing import TYPE_CHECKING, Iterator + +import pytest + +if TYPE_CHECKING: + from typing import List # pylint: disable=ungrouped-imports + + from _pytest import nodes + from _pytest.config import Config + from _pytest.config.argparsing import Parser @contextmanager @@ -12,3 +21,31 @@ def cwd(path: str) -> Iterator[None]: yield finally: os.chdir(old_pwd) + + +def pytest_addoption(parser: "Parser") -> None: + """Add --regenerate-formatting-fixtures option to pytest.""" + parser.addoption( + "--regenerate-formatting-fixtures", + action="store_true", + default=False, + help="Regenerate formatting fixtures with prettier and internal formatter", + ) + + +def pytest_collection_modifyitems(items: "List[nodes.Item]", config: "Config") -> None: + """Skip tests based on --regenerate-formatting-fixtures option.""" + do_regenerate = config.getoption("--regenerate-formatting-fixtures") + skip_other = pytest.mark.skip( + reason="not a formatting_fixture test and " + "--regenerate-formatting-fixtures was specified" + ) + skip_formatting_fixture = pytest.mark.skip( + reason="specify --regenerate-formatting-fixtures to " + "only run formatting_fixtures test" + ) + for item in items: + if do_regenerate and "formatting_fixtures" not in item.keywords: + item.add_marker(skip_other) + elif not do_regenerate and "formatting_fixtures" in item.keywords: + item.add_marker(skip_formatting_fixture) diff --git a/test/fixtures/__init__.py b/test/fixtures/__init__.py new file mode 100644 index 0000000000..6fc2115b82 --- /dev/null +++ b/test/fixtures/__init__.py @@ -0,0 +1 @@ +"""Fixtures used in tests.""" diff --git a/test/fixtures/formatting-after/fmt-1.yml b/test/fixtures/formatting-after/fmt-1.yml index 777e51a4da..053c9cc92c 100644 --- a/test/fixtures/formatting-after/fmt-1.yml +++ b/test/fixtures/formatting-after/fmt-1.yml @@ -44,3 +44,4 @@ overly-indented-vault-value: !vault | 123466303630313 # this file also has 3 newlines at end-of-file instead of one + diff --git a/test/fixtures/formatting-after/fmt-2.yml b/test/fixtures/formatting-after/fmt-2.yml new file mode 100644 index 0000000000..8405b1a1dd --- /dev/null +++ b/test/fixtures/formatting-after/fmt-2.yml @@ -0,0 +1,19 @@ +# preamble/header comment +--- +# initial comment +- foo: bar + +- baz: # over indented + - qwerty + - foobar + animals: # under indented + - crow + - pig + - giraffe + +- nothing: null # null + +- octal: + - 0o123 # YAML 1.2 octal + - 0123 # YAML 1.1 octal + diff --git a/test/fixtures/formatting-before/fmt-2.yml b/test/fixtures/formatting-before/fmt-2.yml new file mode 100644 index 0000000000..d2578d40dd --- /dev/null +++ b/test/fixtures/formatting-before/fmt-2.yml @@ -0,0 +1,19 @@ +# preamble/header comment +--- +# initial comment + - foo: bar + + - baz: # over indented + - qwerty + - foobar + animals: # under indented + - crow + - pig + - giraffe + + - nothing: null # null + + - octal: + - 0o123 # YAML 1.2 octal + - 0123 # YAML 1.1 octal + diff --git a/test/fixtures/formatting-prettier/fmt-1.yml b/test/fixtures/formatting-prettier/fmt-1.yml new file mode 100644 index 0000000000..053c9cc92c --- /dev/null +++ b/test/fixtures/formatting-prettier/fmt-1.yml @@ -0,0 +1,47 @@ +--- +# ^ too many newlines before +foo: bar # This is a comment has extra spaces preceding it + +fruits: # unindented sequence: + - apple + - orange +vegetables: # indented sequence: + - onion + - carrot + +quoting: + - "that should have double quotes" + - "that should remain in single quotes" + - 'a string with " inside' + # next line has some undesired trailing spaces: + - "a string with ' inside" + - can't be sure! + # next line should be converted to use double quotes: + - ["foo", "bar"] + +inline-dictionary: + - { foo: bar } # should add some spacing between curly braces and content + +# YAML 1.1 Boolean-hell: https://yaml.org/type/bool.html +booleans-true: + preferred: true # YAML 1.2 compatible! + answer-1.1: YES + canonical-1.1: y + canonical-upper-1.1: Y + logical-1.1: True + option-1.1: on +booleans-false: + preferred: false # YAML 1.2 compatible! + answer-1.1: NO + canonical-1.1: n + canonical-upper-1.1: N + logical-1.1: False + option-1.1: off + +# ^ double newline should be removed +overly-indented-vault-value: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 123466303630313 + +# this file also has 3 newlines at end-of-file instead of one + diff --git a/test/fixtures/formatting-prettier/fmt-2.yml b/test/fixtures/formatting-prettier/fmt-2.yml new file mode 100644 index 0000000000..8405b1a1dd --- /dev/null +++ b/test/fixtures/formatting-prettier/fmt-2.yml @@ -0,0 +1,19 @@ +# preamble/header comment +--- +# initial comment +- foo: bar + +- baz: # over indented + - qwerty + - foobar + animals: # under indented + - crow + - pig + - giraffe + +- nothing: null # null + +- octal: + - 0o123 # YAML 1.2 octal + - 0123 # YAML 1.1 octal + diff --git a/test/fixtures/test_regenerate_formatting_fixtures.py b/test/fixtures/test_regenerate_formatting_fixtures.py new file mode 100644 index 0000000000..13071bb058 --- /dev/null +++ b/test/fixtures/test_regenerate_formatting_fixtures.py @@ -0,0 +1,39 @@ +"""Test that re-generates formatting fixtures.""" +import shutil +import subprocess +from pathlib import Path + +import pytest + + +@pytest.mark.formatting_fixtures() +def test_regenerate_formatting_fixtures() -> None: + """Re-generate formatting fixtures with prettier and internal formatter. + + Pass ``--regenerate-formatting-fixtures`` to run this and skip all other tests. + This is a "test" because once fixtures are regenerated, + we run prettier again to make sure it does not change files formatted + with our internal formatting code. + """ + print("Looking for prettier on PATH...") + subprocess.check_call(["which", "prettier"]) + + fixtures_dir = Path("test/fixtures/") + fixtures_dir_before = fixtures_dir / "formatting-before" + fixtures_dir_prettier = fixtures_dir / "formatting-prettier" + fixtures_dir_after = fixtures_dir / "formatting-after" + + fixtures_dir_prettier.mkdir(exist_ok=True) + fixtures_dir_after.mkdir(exist_ok=True) + + print("\nCopying before fixtures...") + for fixture in fixtures_dir_before.glob("fmt-[0-9].yml"): + shutil.copy(str(fixture), str(fixtures_dir_prettier / fixture.name)) + shutil.copy(str(fixture), str(fixtures_dir_after / fixture.name)) + + print("\nWriting fixtures with prettier...") + subprocess.check_call(["prettier", "-w", str(fixtures_dir_prettier)]) + # NB: pre-commit end-of-file-fixer can also modify files. + + # prepare ruamel.yaml fixtures (diff in next PR will show how it compares). + subprocess.check_call(["prettier", "-w", str(fixtures_dir_after)])