Repository: pantsbuild/pants

Issue:
2.20 runs ruff and yapf on BUILD files without opting in to them
**Describe the bug**

The default behaviour of `pants update-build-files ::` seems to have changed in 2.20, compared to 2.19. In particular, it seems to now build and run yapf and ruff, in addition to black, without opting in to the ruff or yapf formatters via the `pants.backend.build_files.fmt.*` backends. (https://www.pantsbuild.org/2.20/docs/using-pants/key-concepts/backends#available-stable-backends)

Reproducer:

```shell
cd $(mktemp -d)

cat > pants.toml <<EOF
[GLOBAL]
pants_version = "2.20.0a0"
backend_packages = []
EOF

# https://docs.astral.sh/ruff/formatter/black/#single-element-tuples-are-always-parenthesized
echo '(1, 2),' > BUILD

pants update-build-files ::
```

This sets up a build file that has different expected formatting for black vs. ruff by abuse a difference between them.

Running with `PANTS_VERSION=2.19.0 bash run.sh` (or anything up to `PANTS_VERSION=2.20.0.dev7 bash run.sh`) has output:

```
12:37:40.96 [INFO] Initializing scheduler...
12:37:41.14 [INFO] Scheduler initialized.
12:37:45.89 [INFO] Starting: Building black.pex from resource://pants.backend.python.lint.black/black.lock
12:37:46.76 [INFO] Completed: Building black.pex from resource://pants.backend.python.lint.black/black.lock
12:37:47.37 [INFO] No required changes to BUILD files found.However, there may still be deprecations that `update-build-files` doesn't know how to fix. See https://www.pantsbuild.org/v2.19/docs/upgrade-tips for upgrade tips.
```

Notably: 

- builds black ✅ 
- doesn't reformat ✅ 

Running with `bash run.sh` has output:

```
PANTS_LOCAL_CACHE=false  bash run.sh
12:39:35.21 [INFO] Initializing scheduler...
12:39:35.39 [INFO] Scheduler initialized.
...

12:39:37.04 [INFO] Starting: Building black.pex from resource://pants.backend.python.lint.black/black.lock
12:39:37.82 [INFO] Completed: Building black.pex from resource://pants.backend.python.lint.black/black.lock
12:39:38.11 [INFO] Starting: Building yapf.pex from resource://pants.backend.python.lint.yapf/yapf.lock
12:39:38.86 [INFO] Completed: Building yapf.pex from resource://pants.backend.python.lint.yapf/yapf.lock
12:39:38.97 [INFO] Starting: Building ruff.pex from resource://pants.backend.python.lint.ruff/ruff.lock
12:39:39.88 [INFO] Completed: Building ruff.pex from resource://pants.backend.python.lint.ruff/ruff.lock
Updated BUILD:
  - Format with Ruff
```

Notably: 
- builds black ✅ and ruff ❌ and yapf ❌ 
- reformats with ruff ❌ 


**Pants version**
2.20.0a0

This seems to be a regression between that and 2.20.0.dev7 likely related to #20411.

- https://github.com/pantsbuild/pants/releases/tag/release_2.20.0a0
- https://github.com/pantsbuild/pants/compare/release_2.20.0.dev7...release_2.20.0a0


**OS**
macOS

**Additional info**
N/A


Discussion:
Thanks for noticing I'd filed this @krishnan-chandra, assigned to you based on #20580 existing 😄 

Resolving patch:
diff --git a/src/python/pants/core/goals/update_build_files.py b/src/python/pants/core/goals/update_build_files.py
--- a/src/python/pants/core/goals/update_build_files.py
+++ b/src/python/pants/core/goals/update_build_files.py
@@ -234,10 +234,17 @@ async def update_build_files(
         raise ValueError(f"Unrecognized formatter: {update_build_files_subsystem.formatter}")
 
     for request in union_membership[RewrittenBuildFileRequest]:
-        if update_build_files_subsystem.fmt and issubclass(request, chosen_formatter_request_class):
+        if update_build_files_subsystem.fmt and request == chosen_formatter_request_class:
             rewrite_request_classes.append(request)
 
-        if update_build_files_subsystem.fix_safe_deprecations or not issubclass(
+        if update_build_files_subsystem.fix_safe_deprecations and issubclass(
+            request, DeprecationFixerRequest
+        ):
+            rewrite_request_classes.append(request)
+
+        # If there are other types of requests that aren't the standard formatter
+        # backends or deprecation fixers, add them here.
+        if request not in formatter_to_request_class.values() and not issubclass(
             request, DeprecationFixerRequest
         ):
             rewrite_request_classes.append(request)


Test patch:
diff --git a/src/python/pants/core/goals/update_build_files_test.py b/src/python/pants/core/goals/update_build_files_test.py
--- a/src/python/pants/core/goals/update_build_files_test.py
+++ b/src/python/pants/core/goals/update_build_files_test.py
@@ -74,12 +74,24 @@ def reverse_lines(request: MockRewriteReverseLines) -> RewrittenBuildFile:
 def generic_goal_rule_runner() -> RuleRunner:
     return RuleRunner(
         rules=(
-            update_build_files,
             add_line,
             reverse_lines,
+            format_build_file_with_ruff,
+            format_build_file_with_yapf,
+            update_build_files,
+            *config_files.rules(),
+            *pex.rules(),
+            # Ruff and Yapf are included, but Black isn't because
+            # that's the formatter we enable in pants.toml.
+            # These tests check that Ruff and Yapf are NOT invoked,
+            # but the other rewrite targets are invoked.
+            *Ruff.rules(),
+            *Yapf.rules(),
             *UpdateBuildFilesSubsystem.rules(),
             UnionRule(RewrittenBuildFileRequest, MockRewriteAddLine),
             UnionRule(RewrittenBuildFileRequest, MockRewriteReverseLines),
+            UnionRule(RewrittenBuildFileRequest, FormatWithRuffRequest),
+            UnionRule(RewrittenBuildFileRequest, FormatWithYapfRequest),
         )
     )
 
@@ -204,12 +216,20 @@ def black_rule_runner() -> RuleRunner:
     return RuleRunner(
         rules=(
             format_build_file_with_black,
+            format_build_file_with_ruff,
+            format_build_file_with_yapf,
             update_build_files,
             *config_files.rules(),
             *pex.rules(),
             *Black.rules(),
+            # Even though Ruff and Yapf are included here,
+            # only Black should be used for formatting.
+            *Ruff.rules(),
+            *Yapf.rules(),
             *UpdateBuildFilesSubsystem.rules(),
             UnionRule(RewrittenBuildFileRequest, FormatWithBlackRequest),
+            UnionRule(RewrittenBuildFileRequest, FormatWithRuffRequest),
+            UnionRule(RewrittenBuildFileRequest, FormatWithYapfRequest),
         ),
         target_types=[GenericTarget],
     )