mirror of
https://github.com/home-assistant/core.git
synced 2025-04-19 14:57:52 +00:00
168 lines
4.7 KiB
Python
168 lines
4.7 KiB
Python
"""Validate manifests."""
|
|
|
|
import argparse
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
|
|
from script.util import valid_integration
|
|
|
|
from . import docs, error, gather_info, generate
|
|
from .model import Info
|
|
|
|
TEMPLATES = [
|
|
p.name for p in (Path(__file__).parent / "templates").glob("*") if p.is_dir()
|
|
]
|
|
|
|
|
|
def get_arguments() -> argparse.Namespace:
|
|
"""Get parsed passed in arguments."""
|
|
parser = argparse.ArgumentParser(description="Home Assistant Scaffolder")
|
|
parser.add_argument("template", type=str, choices=TEMPLATES)
|
|
parser.add_argument(
|
|
"--develop", action="store_true", help="Automatically fill in info"
|
|
)
|
|
parser.add_argument(
|
|
"--integration", type=valid_integration, help="Integration to target."
|
|
)
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def run_process(name: str, cmd: list[str], info: Info) -> None:
|
|
"""Run a sub process and handle the result.
|
|
|
|
:param name: The name of the sub process used in reporting.
|
|
:param cmd: The sub process arguments.
|
|
:param info: The Info object.
|
|
:raises subprocess.CalledProcessError: If the subprocess failed.
|
|
|
|
If the sub process was successful print a success message, otherwise
|
|
print an error message and raise a subprocess.CalledProcessError.
|
|
"""
|
|
print(f"Command: {' '.join(cmd)}")
|
|
print()
|
|
result: subprocess.CompletedProcess = subprocess.run(cmd, check=False)
|
|
if result.returncode == 0:
|
|
print()
|
|
print(f"Completed {name} successfully.")
|
|
print()
|
|
return
|
|
|
|
print()
|
|
print(f"Fatal Error: {name} failed with exit code {result.returncode}")
|
|
print()
|
|
if info.is_new:
|
|
print("This is a bug, please report an issue!")
|
|
else:
|
|
print(
|
|
"This may be an existing issue with your integration,",
|
|
"if so fix and run `script.scaffold` again,",
|
|
"otherwise please report an issue.",
|
|
)
|
|
result.check_returncode()
|
|
|
|
|
|
def main() -> int:
|
|
"""Scaffold an integration."""
|
|
if not Path("requirements_all.txt").is_file():
|
|
print("Run from project root")
|
|
return 1
|
|
|
|
args = get_arguments()
|
|
|
|
info = gather_info.gather_info(args)
|
|
print()
|
|
|
|
# If we are calling scaffold on a non-existing integration,
|
|
# We're going to first make it. If we're making an integration,
|
|
# we will also make a config flow to go with it.
|
|
|
|
if info.is_new:
|
|
generate.generate("integration", info)
|
|
|
|
# If it's a new integration and it's not a config flow,
|
|
# create a config flow too.
|
|
if not args.template.startswith("config_flow"):
|
|
if info.helper:
|
|
template = "config_flow_helper"
|
|
elif info.oauth2:
|
|
template = "config_flow_oauth2"
|
|
elif info.authentication or not info.discoverable:
|
|
template = "config_flow"
|
|
else:
|
|
template = "config_flow_discovery"
|
|
|
|
generate.generate(template, info)
|
|
|
|
# If we wanted a new integration, we've already done our work.
|
|
if args.template != "integration":
|
|
generate.generate(args.template, info)
|
|
|
|
# Always output sub commands as the output will contain useful information if a command fails.
|
|
print("Running hassfest to pick up new information.")
|
|
run_process(
|
|
"hassfest",
|
|
[
|
|
"python",
|
|
"-m",
|
|
"script.hassfest",
|
|
"--integration-path",
|
|
str(info.integration_dir),
|
|
"--skip-plugins",
|
|
"quality_scale", # Skip quality scale as it will fail for newly generated integrations.
|
|
],
|
|
info,
|
|
)
|
|
|
|
print("Running gen_requirements_all to pick up new information.")
|
|
run_process(
|
|
"gen_requirements_all",
|
|
["python", "-m", "script.gen_requirements_all"],
|
|
info,
|
|
)
|
|
|
|
print("Running translations to pick up new translation strings.")
|
|
run_process(
|
|
"translations",
|
|
[
|
|
"python",
|
|
"-m",
|
|
"script.translations",
|
|
"develop",
|
|
"--integration",
|
|
info.domain,
|
|
],
|
|
info,
|
|
)
|
|
|
|
if args.develop:
|
|
print("Running tests")
|
|
run_process(
|
|
"pytest",
|
|
[
|
|
"python3",
|
|
"-b",
|
|
"-m",
|
|
"pytest",
|
|
"-vvv",
|
|
f"tests/components/{info.domain}",
|
|
],
|
|
info,
|
|
)
|
|
|
|
docs.print_relevant_docs(args.template, info)
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
sys.exit(main())
|
|
except subprocess.CalledProcessError as err:
|
|
sys.exit(err.returncode)
|
|
except error.ExitApp as err:
|
|
print()
|
|
print(f"Fatal Error: {err.reason}")
|
|
sys.exit(err.exit_code)
|