forked from pantsbuild/pants
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow using Ruff to format BUILD files (pantsbuild#20411)
Closes pantsbuild#20392. In addition to `black` and `yapf`, we will now allow using `ruff` to format build files. This PR contains changes to the `update-build-files` goal and the `ruff` subsystem to enable this.
- Loading branch information
1 parent
0df48c7
commit 3129951
Showing
9 changed files
with
298 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
python_sources() | ||
|
||
python_tests(name="tests") |
Empty file.
115 changes: 115 additions & 0 deletions
115
src/python/pants/backend/build_files/fmt/ruff/integration_test.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
from __future__ import annotations | ||
|
||
import pytest | ||
|
||
from pants.backend.build_files.fmt.ruff.register import RuffRequest | ||
from pants.backend.build_files.fmt.ruff.register import rules as ruff_build_rules | ||
from pants.backend.python.lint.ruff.rules import rules as ruff_fmt_rules | ||
from pants.backend.python.lint.ruff.subsystem import Ruff | ||
from pants.backend.python.lint.ruff.subsystem import rules as ruff_subsystem_rules | ||
from pants.backend.python.target_types import PythonSourcesGeneratorTarget | ||
from pants.core.goals.fmt import FmtResult | ||
from pants.core.util_rules import config_files | ||
from pants.engine.fs import PathGlobs | ||
from pants.engine.internals.native_engine import Snapshot | ||
from pants.testutil.python_interpreter_selection import all_major_minor_python_versions | ||
from pants.testutil.rule_runner import QueryRule, RuleRunner | ||
|
||
|
||
@pytest.fixture | ||
def rule_runner() -> RuleRunner: | ||
return RuleRunner( | ||
rules=[ | ||
*ruff_build_rules(), | ||
*ruff_fmt_rules(), | ||
*ruff_subsystem_rules(), | ||
*config_files.rules(), | ||
QueryRule(FmtResult, (RuffRequest.Batch,)), | ||
], | ||
target_types=[PythonSourcesGeneratorTarget], | ||
) | ||
|
||
|
||
def run_ruff(rule_runner: RuleRunner, *, extra_args: list[str] | None = None) -> FmtResult: | ||
rule_runner.set_options( | ||
["--backend-packages=pants.backend.build_files.fmt.ruff", *(extra_args or ())], | ||
env_inherit={"PATH", "PYENV_ROOT", "HOME"}, | ||
) | ||
snapshot = rule_runner.request(Snapshot, [PathGlobs(["**/BUILD"])]) | ||
fmt_result = rule_runner.request( | ||
FmtResult, | ||
[ | ||
RuffRequest.Batch("", snapshot.files, partition_metadata=None, snapshot=snapshot), | ||
], | ||
) | ||
return fmt_result | ||
|
||
|
||
@pytest.mark.platform_specific_behavior | ||
@pytest.mark.parametrize( | ||
"major_minor_interpreter", | ||
all_major_minor_python_versions(Ruff.default_interpreter_constraints), | ||
) | ||
def test_passing(rule_runner: RuleRunner, major_minor_interpreter: str) -> None: | ||
rule_runner.write_files({"BUILD": 'python_sources(name="t")\n'}) | ||
interpreter_constraint = f"=={major_minor_interpreter}.*" | ||
fmt_result = run_ruff( | ||
rule_runner, | ||
extra_args=[f"--ruff-interpreter-constraints=['{interpreter_constraint}']"], | ||
) | ||
assert "1 file left unchanged" in fmt_result.stdout | ||
assert fmt_result.output == rule_runner.make_snapshot({"BUILD": 'python_sources(name="t")\n'}) | ||
assert fmt_result.did_change is False | ||
|
||
|
||
def test_failing(rule_runner: RuleRunner) -> None: | ||
rule_runner.write_files({"BUILD": "python_sources(name='t')\n"}) | ||
fmt_result = run_ruff(rule_runner) | ||
assert "1 file reformatted" in fmt_result.stdout | ||
assert fmt_result.output == rule_runner.make_snapshot({"BUILD": 'python_sources(name="t")\n'}) | ||
assert fmt_result.did_change is True | ||
|
||
|
||
def test_multiple_files(rule_runner: RuleRunner) -> None: | ||
rule_runner.write_files( | ||
{ | ||
"good/BUILD": 'python_sources(name="t")\n', | ||
"bad/BUILD": "python_sources(name='t')\n", | ||
} | ||
) | ||
fmt_result = run_ruff(rule_runner) | ||
assert "1 file reformatted, 1 file left unchanged" in fmt_result.stdout | ||
assert fmt_result.output == rule_runner.make_snapshot( | ||
{"good/BUILD": 'python_sources(name="t")\n', "bad/BUILD": 'python_sources(name="t")\n'} | ||
) | ||
assert fmt_result.did_change is True | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"config_path,extra_args", | ||
(["pyproject.toml", []], ["custom_config.toml", ["--ruff-config=custom_config.toml"]]), | ||
) | ||
def test_config_file(rule_runner: RuleRunner, config_path: str, extra_args: list[str]) -> None: | ||
# Force single-quote formatting to pass config and ensure there are no changes. | ||
# Use the `tool.ruff` key in pyproject.toml, but don't include in custom config. | ||
config_content = ( | ||
'[tool.ruff.format]\nquote-style = "single"\n' | ||
if config_path == "pyproject.toml" | ||
else '[format]\nquote-style = "single"\n' | ||
) | ||
rule_runner.write_files( | ||
{ | ||
"BUILD": "python_sources(name='t')\n", | ||
config_path: config_content, | ||
} | ||
) | ||
before_file_content = rule_runner.read_file("BUILD") | ||
fmt_result = run_ruff(rule_runner, extra_args=extra_args) | ||
after_file_content = rule_runner.read_file("BUILD") | ||
|
||
assert before_file_content == after_file_content | ||
assert fmt_result.output == rule_runner.make_snapshot({"BUILD": "python_sources(name='t')\n"}) | ||
assert fmt_result.did_change is False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). | ||
# Licensed under the Apache License, Version 2.0 (see LICENSE). | ||
|
||
from pants.backend.build_files.fmt.base import FmtBuildFilesRequest | ||
from pants.backend.python.lint.ruff import subsystem as ruff_subsystem | ||
from pants.backend.python.lint.ruff.rules import _run_ruff_fmt | ||
from pants.backend.python.lint.ruff.subsystem import Ruff | ||
from pants.backend.python.subsystems.python_tool_base import get_lockfile_interpreter_constraints | ||
from pants.core.goals.fmt import FmtResult | ||
from pants.engine.rules import collect_rules, rule | ||
from pants.util.logging import LogLevel | ||
|
||
|
||
class RuffRequest(FmtBuildFilesRequest): | ||
tool_subsystem = Ruff | ||
|
||
|
||
@rule(desc="Format with Ruff", level=LogLevel.DEBUG) | ||
async def ruff_fmt(request: RuffRequest.Batch, ruff: Ruff) -> FmtResult: | ||
ruff_ics = await get_lockfile_interpreter_constraints(ruff) | ||
return await _run_ruff_fmt(request, ruff, ruff_ics) | ||
|
||
|
||
def rules(): | ||
return [ | ||
*collect_rules(), | ||
*RuffRequest.rules(), | ||
*ruff_subsystem.rules(), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.