ha-deploy-kit 0.1.1__tar.gz → 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/CHANGELOG.md +13 -0
  2. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/PKG-INFO +2 -2
  3. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/README.md +1 -1
  4. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/pyproject.toml +1 -1
  5. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/ha/repairs_flow.py +7 -14
  6. ha_deploy_kit-0.1.2/src/ha_deploy_kit/metadata/strings.snippet.fixflow.json +15 -0
  7. ha_deploy_kit-0.1.2/tests/ha/test_repairs_flow.py +35 -0
  8. ha_deploy_kit-0.1.1/src/ha_deploy_kit/metadata/strings.snippet.fixflow.json +0 -21
  9. ha_deploy_kit-0.1.1/tests/ha/test_repairs_flow.py +0 -54
  10. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/.coveragerc-ha +0 -0
  11. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/.github/workflows/release.yml +0 -0
  12. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/.github/workflows/validate.yml +0 -0
  13. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/.gitignore +0 -0
  14. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/LICENSE +0 -0
  15. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/docs/adopting.md +0 -0
  16. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/docs/configuration.md +0 -0
  17. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/docs/install.md +0 -0
  18. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/docs/releasing.md +0 -0
  19. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/examples/backend_only/.env.example +0 -0
  20. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/examples/backend_only/deploy.py +0 -0
  21. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/examples/backend_only/deploy.sh +0 -0
  22. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/examples/frontend_card/.env.example +0 -0
  23. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/examples/frontend_card/deploy.py +0 -0
  24. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/examples/frontend_card/deploy.sh +0 -0
  25. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/examples/frontend_card/ha_adapter.py +0 -0
  26. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/examples/synthetic_widget/deploy.py +0 -0
  27. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/examples/synthetic_widget/ha_adapter.py +0 -0
  28. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/__init__.py +0 -0
  29. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/cli.py +0 -0
  30. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/comparison.py +0 -0
  31. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/config.py +0 -0
  32. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/frontend.py +0 -0
  33. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/ha/__init__.py +0 -0
  34. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/ha/repairs_issue.py +0 -0
  35. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/ha/service.py +0 -0
  36. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/ha/serving.py +0 -0
  37. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/inventory.py +0 -0
  38. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/metadata/services.yaml.tmpl +0 -0
  39. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/metadata/strings.snippet.json +0 -0
  40. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/notify.py +0 -0
  41. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/settings.py +0 -0
  42. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/src/ha_deploy_kit/transport.py +0 -0
  43. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/conftest.py +0 -0
  44. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/ha/conftest.py +0 -0
  45. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/ha/test_example_adapters.py +0 -0
  46. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/ha/test_real_http_to_service.py +0 -0
  47. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/ha/test_repairs_issue.py +0 -0
  48. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/ha/test_service.py +0 -0
  49. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/ha/test_serving.py +0 -0
  50. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/test_cli.py +0 -0
  51. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/test_comparison.py +0 -0
  52. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/test_config.py +0 -0
  53. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/test_frontend.py +0 -0
  54. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/test_installed_smoke.py +0 -0
  55. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/test_inventory.py +0 -0
  56. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/test_multi_consumer.py +0 -0
  57. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/test_notify.py +0 -0
  58. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/test_packaging.py +0 -0
  59. {ha_deploy_kit-0.1.1 → ha_deploy_kit-0.1.2}/tests/test_transport.py +0 -0
@@ -1,6 +1,19 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v0.1.2 (2026-10-29)
5
+
6
+ ### Bug Fixes
7
+
8
+ - **ha**: Confirm restart via a dialog instead of a checkbox
9
+ ([`aeaf825`](https://github.com/latrekc-meta/ha-deploy-kit/commit/aeaf82541dced2e3e77828b97f28c34dab5e361a))
10
+
11
+ The checkbox step added friction without benefit: opening the Repairs issue already shows a
12
+ confirmation dialog, and the restart should fire when the user submits it. Drop the required
13
+ confirm checkbox and the confirm_required error; restart only on submit of the dialog. Trim the
14
+ fix-flow strings snippet back to title + description.
15
+
16
+
4
17
  ## v0.1.1 (2026-10-29)
5
18
 
6
19
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ha-deploy-kit
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: HA-free SSH deploy / compare / notify / optional-frontend toolkit for Home Assistant custom components
5
5
  Project-URL: Homepage, https://github.com/latrekc-meta/ha-deploy-kit
6
6
  Project-URL: Repository, https://github.com/latrekc-meta/ha-deploy-kit
@@ -110,7 +110,7 @@ how releases are published.
110
110
  | `ha.async_register_restart_service(hass, domain, ...)` | `ha_deploy_kit.ha` | Idempotently register the restart service (empty schema). Pass `fixable=True` for a one-click Repairs card (pair with the fix flow). |
111
111
  | `ha.async_raise_restart_issue(hass, domain, ...)` | `ha_deploy_kit.ha` | Raise the deduplicated, non-persistent restart Repairs issue. |
112
112
  | `ha.async_clear_restart_issue(hass, domain, ...)` | `ha_deploy_kit.ha` | Clear the restart issue. |
113
- | `ha.async_create_restart_fix_flow(hass, issue_id, ...)` | `ha_deploy_kit.ha` | Optional opt-in confirm-and-restart flow (restart only after the user ticks the confirmation checkbox). |
113
+ | `ha.async_create_restart_fix_flow(hass, issue_id, ...)` | `ha_deploy_kit.ha` | Optional opt-in confirm-and-restart flow (shows a confirmation dialog; restart only when the user submits it). |
114
114
  | `ha.register_card_serving(hass, domain, lovelace_dir, card_url)` | `ha_deploy_kit.ha` | Serve the card and register it as a frontend module. |
115
115
 
116
116
  ## CLI
@@ -62,7 +62,7 @@ how releases are published.
62
62
  | `ha.async_register_restart_service(hass, domain, ...)` | `ha_deploy_kit.ha` | Idempotently register the restart service (empty schema). Pass `fixable=True` for a one-click Repairs card (pair with the fix flow). |
63
63
  | `ha.async_raise_restart_issue(hass, domain, ...)` | `ha_deploy_kit.ha` | Raise the deduplicated, non-persistent restart Repairs issue. |
64
64
  | `ha.async_clear_restart_issue(hass, domain, ...)` | `ha_deploy_kit.ha` | Clear the restart issue. |
65
- | `ha.async_create_restart_fix_flow(hass, issue_id, ...)` | `ha_deploy_kit.ha` | Optional opt-in confirm-and-restart flow (restart only after the user ticks the confirmation checkbox). |
65
+ | `ha.async_create_restart_fix_flow(hass, issue_id, ...)` | `ha_deploy_kit.ha` | Optional opt-in confirm-and-restart flow (shows a confirmation dialog; restart only when the user submits it). |
66
66
  | `ha.register_card_serving(hass, domain, lovelace_dir, card_url)` | `ha_deploy_kit.ha` | Serve the card and register it as a frontend module. |
67
67
 
68
68
  ## CLI
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ha-deploy-kit"
7
- version = "0.1.1"
7
+ version = "0.1.2"
8
8
  description = "HA-free SSH deploy / compare / notify / optional-frontend toolkit for Home Assistant custom components"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -1,10 +1,9 @@
1
1
  """Optional opt-in confirm-and-restart Repairs flow.
2
2
 
3
- The restart happens ONLY when the user explicitly ticks the confirmation checkbox
4
- and submits. An empty-schema form can be submitted with nothing selected, so a
5
- required ``confirm`` boolean makes the restart a deliberate choice. No executable
6
- restart lives in the core engine; this flow is the single opt-in place a consumer
7
- may wire it.
3
+ The restart happens ONLY after the user submits the confirmation dialog. Opening
4
+ the Repairs issue shows a dialog describing the restart; clicking submit is the
5
+ explicit confirmation. No executable restart lives in the core engine; this flow
6
+ is the single opt-in place a consumer may wire it.
8
7
  """
9
8
 
10
9
  from __future__ import annotations
@@ -18,11 +17,9 @@ if TYPE_CHECKING:
18
17
  from homeassistant.core import HomeAssistant
19
18
  from homeassistant.data_entry_flow import FlowResult
20
19
 
21
- _CONFIRM_SCHEMA = vol.Schema({vol.Required("confirm", default=False): bool})
22
-
23
20
 
24
21
  class _RestartRequiredFixFlow(RepairsFlow):
25
- """Restarts only after the user ticks the confirmation checkbox and submits."""
22
+ """Shows a confirmation dialog, then restarts only when the user submits it."""
26
23
 
27
24
  async def async_step_init(
28
25
  self, user_input: dict[str, Any] | None = None
@@ -32,13 +29,9 @@ class _RestartRequiredFixFlow(RepairsFlow):
32
29
  async def async_step_confirm_restart(
33
30
  self, user_input: dict[str, Any] | None = None
34
31
  ) -> FlowResult:
35
- if not (user_input and user_input.get("confirm")):
36
- # First render, or submitted without ticking the box: re-show the
37
- # form and never restart.
32
+ if user_input is None:
38
33
  return self.async_show_form(
39
- step_id="confirm_restart",
40
- data_schema=_CONFIRM_SCHEMA,
41
- errors={"base": "confirm_required"} if user_input else None,
34
+ step_id="confirm_restart", data_schema=vol.Schema({})
42
35
  )
43
36
  await self.hass.services.async_call("homeassistant", "restart", blocking=False)
44
37
  return self.async_create_entry(title="", data={})
@@ -0,0 +1,15 @@
1
+ {
2
+ "issues": {
3
+ "restart_required": {
4
+ "title": "Restart required to finish updating",
5
+ "fix_flow": {
6
+ "step": {
7
+ "confirm_restart": {
8
+ "title": "Restart Home Assistant",
9
+ "description": "Newly deployed code is on disk. Click submit to restart Home Assistant now and load it."
10
+ }
11
+ }
12
+ }
13
+ }
14
+ }
15
+ }
@@ -0,0 +1,35 @@
1
+ import pytest
2
+ from pytest_homeassistant_custom_component.common import async_mock_service
3
+
4
+ from ha_deploy_kit.ha import async_create_restart_fix_flow
5
+
6
+ pytestmark = pytest.mark.ha
7
+
8
+
9
+ async def test_showing_the_form_never_restarts(hass):
10
+ calls = async_mock_service(hass, "homeassistant", "restart")
11
+
12
+ flow = async_create_restart_fix_flow(hass, "restart_required")
13
+ assert flow is not None
14
+ flow.hass = hass
15
+
16
+ shown = await flow.async_step_init()
17
+ assert shown["type"] == "form"
18
+ assert shown["step_id"] == "confirm_restart"
19
+ assert len(calls) == 0 # merely showing the confirmation dialog never restarts
20
+
21
+
22
+ async def test_restart_only_after_submitting_the_dialog(hass):
23
+ calls = async_mock_service(hass, "homeassistant", "restart")
24
+
25
+ flow = async_create_restart_fix_flow(hass, "restart_required")
26
+ assert flow is not None
27
+ flow.hass = hass
28
+
29
+ result = await flow.async_step_confirm_restart({})
30
+ assert result["type"] == "create_entry"
31
+ assert len(calls) == 1 # restart only when the user submits the dialog
32
+
33
+
34
+ async def test_fix_flow_other_issue_returns_none(hass):
35
+ assert async_create_restart_fix_flow(hass, "something_else") is None
@@ -1,21 +0,0 @@
1
- {
2
- "issues": {
3
- "restart_required": {
4
- "title": "Restart required to finish updating",
5
- "fix_flow": {
6
- "step": {
7
- "confirm_restart": {
8
- "title": "Restart Home Assistant",
9
- "description": "Restart Home Assistant now to load the newly deployed code? Tick the box below to confirm.",
10
- "data": {
11
- "confirm": "Yes, restart Home Assistant now"
12
- }
13
- }
14
- },
15
- "error": {
16
- "confirm_required": "Tick the box to confirm the restart, or close this dialog to cancel."
17
- }
18
- }
19
- }
20
- }
21
- }
@@ -1,54 +0,0 @@
1
- import pytest
2
- from pytest_homeassistant_custom_component.common import async_mock_service
3
-
4
- from ha_deploy_kit.ha import async_create_restart_fix_flow
5
-
6
- pytestmark = pytest.mark.ha
7
-
8
-
9
- async def test_showing_the_form_never_restarts(hass):
10
- calls = async_mock_service(hass, "homeassistant", "restart")
11
-
12
- flow = async_create_restart_fix_flow(hass, "restart_required")
13
- assert flow is not None
14
- flow.hass = hass
15
-
16
- shown = await flow.async_step_init()
17
- assert shown["type"] == "form"
18
- assert shown["step_id"] == "confirm_restart"
19
- assert len(calls) == 0 # merely showing the form never restarts
20
-
21
-
22
- async def test_submitting_without_confirming_does_not_restart(hass):
23
- calls = async_mock_service(hass, "homeassistant", "restart")
24
-
25
- flow = async_create_restart_fix_flow(hass, "restart_required")
26
- assert flow is not None
27
- flow.hass = hass
28
-
29
- # A bare submit (checkbox left unticked) must NOT restart; re-show the form.
30
- unticked = await flow.async_step_confirm_restart({"confirm": False})
31
- assert unticked["type"] == "form"
32
- assert unticked["step_id"] == "confirm_restart"
33
- assert len(calls) == 0
34
-
35
- # An empty submit is treated the same as an unticked checkbox.
36
- empty = await flow.async_step_confirm_restart({})
37
- assert empty["type"] == "form"
38
- assert len(calls) == 0
39
-
40
-
41
- async def test_restart_only_after_explicit_confirmation(hass):
42
- calls = async_mock_service(hass, "homeassistant", "restart")
43
-
44
- flow = async_create_restart_fix_flow(hass, "restart_required")
45
- assert flow is not None
46
- flow.hass = hass
47
-
48
- result = await flow.async_step_confirm_restart({"confirm": True})
49
- assert result["type"] == "create_entry"
50
- assert len(calls) == 1 # restart only on explicit, ticked confirmation
51
-
52
-
53
- async def test_fix_flow_other_issue_returns_none(hass):
54
- assert async_create_restart_fix_flow(hass, "something_else") is None
File without changes
File without changes