Files
core/script/scaffold/__main__.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

168 lines
4.7 KiB
Python
Raw Permalink Normal View History

"""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
2025-02-19 19:23:29 +00:00
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()
2025-02-19 19:23:29 +00:00
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"
2022-03-22 19:51:24 +01:00
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.")
2025-02-19 19:23:29 +00:00
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.")
2025-02-19 19:23:29 +00:00
run_process(
"gen_requirements_all",
["python", "-m", "script.gen_requirements_all"],
info,
)
2025-02-19 19:23:29 +00:00
print("Running translations to pick up new translation strings.")
run_process(
"translations",
[
"python",
"-m",
"script.translations",
"develop",
"--integration",
info.domain,
],
2025-02-19 19:23:29 +00:00
info,
)
if args.develop:
print("Running tests")
2025-02-19 19:23:29 +00:00
run_process(
"pytest",
[
"python3",
"-b",
"-m",
"pytest",
"-vvv",
f"tests/components/{info.domain}",
],
2025-02-19 19:23:29 +00:00
info,
2023-08-19 15:17:17 +03:00
)
docs.print_relevant_docs(args.template, info)
return 0
if __name__ == "__main__":
try:
sys.exit(main())
2025-02-19 19:23:29 +00:00
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)