tools/upgrade/commands/expand_target_coverage.py (86 lines of code) (raw):
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
import argparse
import logging
from pathlib import Path
from typing import Optional
from typing_extensions import Final
from ..configuration import Configuration
from ..filesystem import LocalMode, find_files, path_exists
from ..repository import Repository
from .command import CommandArguments, ErrorSource, ErrorSuppressingCommand
LOG: logging.Logger = logging.getLogger(__name__)
class ExpandTargetCoverage(ErrorSuppressingCommand):
def __init__(
self,
command_arguments: CommandArguments,
*,
repository: Repository,
local_configuration: Optional[str],
fixme_threshold: bool,
) -> None:
super().__init__(command_arguments, repository)
self._local_configuration: Final[Optional[str]] = local_configuration
self._fixme_threshold: bool = fixme_threshold
@staticmethod
def from_arguments(
arguments: argparse.Namespace, repository: Repository
) -> "ExpandTargetCoverage":
command_arguments = CommandArguments.from_arguments(arguments)
return ExpandTargetCoverage(
command_arguments,
repository=repository,
local_configuration=arguments.local_configuration,
fixme_threshold=arguments.fixme_threshold,
)
@classmethod
# pyre-fixme[40]: Non-static method `add_arguments` cannot override a static
# method defined in `ErrorSuppressingCommand`.
def add_arguments(cls, parser: argparse.ArgumentParser) -> None:
super(ExpandTargetCoverage, cls).add_arguments(parser)
parser.set_defaults(command=cls.from_arguments)
parser.add_argument(
"-l",
"--local-configuration",
type=path_exists,
help="Path to project root with local configuration",
)
parser.add_argument(
"--fixme-threshold",
type=int,
help="Ignore all errors in a file if fixme count exceeds threshold.",
)
def run(self) -> None:
local_root = self._local_configuration
local_root = Path(local_root) if local_root else Path.cwd()
# Do not change if configurations exist below given root
existing_configurations = find_files(local_root, ".pyre_configuration.local")
if existing_configurations and not existing_configurations == [
str(local_root / ".pyre_configuration.local")
]:
LOG.warning(
"Cannot expand targets because nested configurations exist:\n%s",
"\n".join(existing_configurations),
)
return
# Expand coverage
local_configuration = Configuration.find_local_configuration(local_root)
if not local_configuration:
LOG.warning("Could not find a local configuration to codemod.")
return
LOG.info("Expanding typecheck targets in `%s`", local_configuration)
configuration = Configuration(local_configuration)
existing_targets = configuration.targets
glob_target = "//{}/...".format(str(local_root))
if existing_targets == [glob_target]:
LOG.info("Configuration is already fully expanded.")
return
configuration.add_targets([glob_target])
configuration.deduplicate_targets()
configuration.write()
# Suppress errors
self._get_and_suppress_errors(
configuration,
error_source=ErrorSource.GENERATE,
fixme_threshold=self._fixme_threshold,
fixme_threshold_fallback_mode=LocalMode.IGNORE,
)
self._repository.commit_changes(
commit=(not self._no_commit),
title=f"Expand target type coverage in {local_root}",
summary="Expanding type coverage of targets in configuration.",
set_dependencies=False,
)