mirror of
https://github.com/esphome/esphome.git
synced 2026-05-23 11:16:52 +08:00
[cli] Add config-hash command (#15548)
Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
@@ -1415,6 +1415,15 @@ def command_config(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
return 0
|
||||
|
||||
|
||||
def command_config_hash(args: ArgsProtocol, config: ConfigType) -> int | None:
|
||||
# generating code might modify config, so it must be done in order to generate
|
||||
# a hash that will match what was generated when compiling and then running
|
||||
# on the device
|
||||
generate_cpp_contents(config)
|
||||
safe_print(f"0x{CORE.config_hash:08x}")
|
||||
return 0
|
||||
|
||||
|
||||
def command_vscode(args: ArgsProtocol) -> int | None:
|
||||
from esphome import vscode
|
||||
|
||||
@@ -1950,6 +1959,7 @@ PRE_CONFIG_ACTIONS = {
|
||||
|
||||
POST_CONFIG_ACTIONS = {
|
||||
"config": command_config,
|
||||
"config-hash": command_config_hash,
|
||||
"compile": command_compile,
|
||||
"upload": command_upload,
|
||||
"logs": command_logs,
|
||||
@@ -2063,6 +2073,13 @@ def parse_args(argv):
|
||||
"--show-secrets", help="Show secrets in output.", action="store_true"
|
||||
)
|
||||
|
||||
parser_config_hash = subparsers.add_parser(
|
||||
"config-hash", help="Calculate the hash of the configuration."
|
||||
)
|
||||
parser_config_hash.add_argument(
|
||||
"configuration", help="Your YAML configuration file(s).", nargs="+"
|
||||
)
|
||||
|
||||
parser_compile = subparsers.add_parser(
|
||||
"compile", help="Read the configuration and compile a program."
|
||||
)
|
||||
|
||||
@@ -29,6 +29,7 @@ from esphome.__main__ import (
|
||||
command_analyze_memory,
|
||||
command_bundle,
|
||||
command_clean_all,
|
||||
command_config_hash,
|
||||
command_rename,
|
||||
command_run,
|
||||
command_update_all,
|
||||
@@ -3439,6 +3440,33 @@ def test_command_wizard(tmp_path: Path) -> None:
|
||||
mock_wizard.assert_called_once_with(config_file)
|
||||
|
||||
|
||||
def test_command_config_hash(
|
||||
tmp_path: Path,
|
||||
capfd: CaptureFixture[str],
|
||||
) -> None:
|
||||
"""command_config_hash runs codegen then prints CORE.config_hash.
|
||||
|
||||
The printed format must match `0x{config_hash:08x}` used by
|
||||
generate_build_info_data_cpp so the value can be compared byte-for-byte
|
||||
against the ESPHOME_CONFIG_HASH embedded in firmware.
|
||||
"""
|
||||
setup_core(tmp_path=tmp_path, config={"esphome": {"name": "test"}})
|
||||
args = MockArgs()
|
||||
|
||||
# generate_cpp_contents requires real components to be loaded; mock it out
|
||||
# so this test isolates the command's output contract. The command must
|
||||
# still call it (codegen can mutate config, which affects the hash).
|
||||
with patch("esphome.__main__.generate_cpp_contents") as mock_generate:
|
||||
result = command_config_hash(args, CORE.config)
|
||||
|
||||
assert result == 0
|
||||
mock_generate.assert_called_once_with(CORE.config)
|
||||
|
||||
output = strip_ansi_codes(capfd.readouterr().out).strip()
|
||||
assert re.fullmatch(r"0x[0-9a-f]{8}", output)
|
||||
assert output == f"0x{CORE.config_hash:08x}"
|
||||
|
||||
|
||||
def test_command_rename_invalid_characters(
|
||||
tmp_path: Path, capfd: CaptureFixture[str]
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user