diff --git a/homeassistant/components/ecobee/notify.py b/homeassistant/components/ecobee/notify.py index b9dafae0f4e..167233e4071 100644 --- a/homeassistant/components/ecobee/notify.py +++ b/homeassistant/components/ecobee/notify.py @@ -43,7 +43,9 @@ class EcobeeNotificationService(BaseNotificationService): async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message and raise issue.""" - migrate_notify_issue(self.hass, DOMAIN, "Ecobee", "2024.11.0") + migrate_notify_issue( + self.hass, DOMAIN, "Ecobee", "2024.11.0", service_name=self._service_name + ) await self.hass.async_add_executor_job( partial(self.send_message, message, **kwargs) ) diff --git a/homeassistant/components/file/notify.py b/homeassistant/components/file/notify.py index b51be280e75..244bd69aa32 100644 --- a/homeassistant/components/file/notify.py +++ b/homeassistant/components/file/notify.py @@ -69,7 +69,9 @@ class FileNotificationService(BaseNotificationService): """Send a message to a file.""" # The use of the legacy notify service was deprecated with HA Core 2024.6.0 # and will be removed with HA Core 2024.12 - migrate_notify_issue(self.hass, DOMAIN, "File", "2024.12.0") + migrate_notify_issue( + self.hass, DOMAIN, "File", "2024.12.0", service_name=self._service_name + ) await self.hass.async_add_executor_job( partial(self.send_message, message, **kwargs) ) diff --git a/homeassistant/components/knx/notify.py b/homeassistant/components/knx/notify.py index 1b6cd325f21..997bdb81057 100644 --- a/homeassistant/components/knx/notify.py +++ b/homeassistant/components/knx/notify.py @@ -60,7 +60,9 @@ class KNXNotificationService(BaseNotificationService): async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send a notification to knx bus.""" - migrate_notify_issue(self.hass, DOMAIN, "KNX", "2024.11.0") + migrate_notify_issue( + self.hass, DOMAIN, "KNX", "2024.11.0", service_name=self._service_name + ) if "target" in kwargs: await self._async_send_to_device(message, kwargs["target"]) else: diff --git a/homeassistant/components/notify/repairs.py b/homeassistant/components/notify/repairs.py index 5c91a9a4731..d188f07c2ed 100644 --- a/homeassistant/components/notify/repairs.py +++ b/homeassistant/components/notify/repairs.py @@ -12,9 +12,31 @@ from .const import DOMAIN @callback def migrate_notify_issue( - hass: HomeAssistant, domain: str, integration_title: str, breaks_in_ha_version: str + hass: HomeAssistant, + domain: str, + integration_title: str, + breaks_in_ha_version: str, + service_name: str | None = None, ) -> None: """Ensure an issue is registered.""" + if service_name is not None: + ir.async_create_issue( + hass, + DOMAIN, + f"migrate_notify_{domain}_{service_name}", + breaks_in_ha_version=breaks_in_ha_version, + issue_domain=domain, + is_fixable=True, + is_persistent=True, + translation_key="migrate_notify_service", + translation_placeholders={ + "domain": domain, + "integration_title": integration_title, + "service_name": service_name, + }, + severity=ir.IssueSeverity.WARNING, + ) + return ir.async_create_issue( hass, DOMAIN, diff --git a/homeassistant/components/notify/strings.json b/homeassistant/components/notify/strings.json index 96482f5a7d5..947b192c4cd 100644 --- a/homeassistant/components/notify/strings.json +++ b/homeassistant/components/notify/strings.json @@ -72,6 +72,17 @@ } } } + }, + "migrate_notify_service": { + "title": "Legacy service `notify.{service_name}` stll being used", + "fix_flow": { + "step": { + "confirm": { + "description": "The {integration_title} `notify.{service_name}` service is migrated, but it seems the old `notify` service is still being used.\n\nA new `notify` entity is available now to replace each legacy `notify` service.\n\nUpdate any automations or scripts to use the new `notify.send_message` service exposed with this new entity. When this is done, select Submit and restart Home Assistant.", + "title": "Migrate legacy {integration_title} notify service for domain `{domain}`" + } + } + } } } } diff --git a/homeassistant/components/tibber/notify.py b/homeassistant/components/tibber/notify.py index 24ae86c9e7f..1c9f86ed502 100644 --- a/homeassistant/components/tibber/notify.py +++ b/homeassistant/components/tibber/notify.py @@ -50,7 +50,13 @@ class TibberNotificationService(BaseNotificationService): async def async_send_message(self, message: str = "", **kwargs: Any) -> None: """Send a message to Tibber devices.""" - migrate_notify_issue(self.hass, TIBBER_DOMAIN, "Tibber", "2024.12.0") + migrate_notify_issue( + self.hass, + TIBBER_DOMAIN, + "Tibber", + "2024.12.0", + service_name=self._service_name, + ) title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) try: await self._notify(title=title, message=message) diff --git a/tests/components/ecobee/test_repairs.py b/tests/components/ecobee/test_repairs.py index 897594c582f..9821d31ac64 100644 --- a/tests/components/ecobee/test_repairs.py +++ b/tests/components/ecobee/test_repairs.py @@ -49,13 +49,13 @@ async def test_ecobee_repair_flow( # Assert the issue is present assert issue_registry.async_get_issue( domain="notify", - issue_id=f"migrate_notify_{DOMAIN}", + issue_id=f"migrate_notify_{DOMAIN}_{DOMAIN}", ) assert len(issue_registry.issues) == 1 url = RepairsFlowIndexView.url resp = await http_client.post( - url, json={"handler": "notify", "issue_id": f"migrate_notify_{DOMAIN}"} + url, json={"handler": "notify", "issue_id": f"migrate_notify_{DOMAIN}_{DOMAIN}"} ) assert resp.status == HTTPStatus.OK data = await resp.json() @@ -74,6 +74,6 @@ async def test_ecobee_repair_flow( # Assert the issue is no longer present assert not issue_registry.async_get_issue( domain="notify", - issue_id="migrate_notify", + issue_id=f"migrate_notify_{DOMAIN}_{DOMAIN}", ) assert len(issue_registry.issues) == 0 diff --git a/tests/components/knx/test_repairs.py b/tests/components/knx/test_repairs.py index 025f298e123..690d6e450cb 100644 --- a/tests/components/knx/test_repairs.py +++ b/tests/components/knx/test_repairs.py @@ -55,13 +55,13 @@ async def test_knx_notify_service_issue( assert len(issue_registry.issues) == 1 assert issue_registry.async_get_issue( domain="notify", - issue_id=f"migrate_notify_{DOMAIN}", + issue_id=f"migrate_notify_{DOMAIN}_notify", ) # Test confirm step in repair flow resp = await http_client.post( RepairsFlowIndexView.url, - json={"handler": "notify", "issue_id": f"migrate_notify_{DOMAIN}"}, + json={"handler": "notify", "issue_id": f"migrate_notify_{DOMAIN}_notify"}, ) assert resp.status == HTTPStatus.OK data = await resp.json() @@ -79,6 +79,6 @@ async def test_knx_notify_service_issue( # Assert the issue is no longer present assert not issue_registry.async_get_issue( domain="notify", - issue_id=f"migrate_notify_{DOMAIN}", + issue_id=f"migrate_notify_{DOMAIN}_notify", ) assert len(issue_registry.issues) == 0 diff --git a/tests/components/notify/test_repairs.py b/tests/components/notify/test_repairs.py index f4e016418fe..fef5818e1e6 100644 --- a/tests/components/notify/test_repairs.py +++ b/tests/components/notify/test_repairs.py @@ -3,6 +3,8 @@ from http import HTTPStatus from unittest.mock import AsyncMock +import pytest + from homeassistant.components.notify import ( DOMAIN as NOTIFY_DOMAIN, migrate_notify_issue, @@ -24,11 +26,17 @@ from tests.typing import ClientSessionGenerator THERMOSTAT_ID = 0 +@pytest.mark.usefixtures("config_flow_fixture") +@pytest.mark.parametrize( + ("service_name", "translation_key"), + [(None, "migrate_notify_test"), ("bla", "migrate_notify_test_bla")], +) async def test_notify_migration_repair_flow( hass: HomeAssistant, hass_client: ClientSessionGenerator, issue_registry: ir.IssueRegistry, - config_flow_fixture: None, + service_name: str | None, + translation_key: str, ) -> None: """Test the notify service repair flow is triggered.""" await async_setup_component(hass, NOTIFY_DOMAIN, {}) @@ -49,18 +57,18 @@ async def test_notify_migration_repair_flow( assert await hass.config_entries.async_setup(config_entry.entry_id) # Simulate legacy service being used and issue being registered - migrate_notify_issue(hass, "test", "Test", "2024.12.0") + migrate_notify_issue(hass, "test", "Test", "2024.12.0", service_name=service_name) await hass.async_block_till_done() # Assert the issue is present assert issue_registry.async_get_issue( domain=NOTIFY_DOMAIN, - issue_id="migrate_notify_test", + issue_id=translation_key, ) assert len(issue_registry.issues) == 1 url = RepairsFlowIndexView.url resp = await http_client.post( - url, json={"handler": NOTIFY_DOMAIN, "issue_id": "migrate_notify_test"} + url, json={"handler": NOTIFY_DOMAIN, "issue_id": translation_key} ) assert resp.status == HTTPStatus.OK data = await resp.json() @@ -79,6 +87,6 @@ async def test_notify_migration_repair_flow( # Assert the issue is no longer present assert not issue_registry.async_get_issue( domain=NOTIFY_DOMAIN, - issue_id="migrate_notify_test", + issue_id=translation_key, ) assert len(issue_registry.issues) == 0 diff --git a/tests/components/tibber/test_repairs.py b/tests/components/tibber/test_repairs.py index 9aaec81618d..89e85e5f8e1 100644 --- a/tests/components/tibber/test_repairs.py +++ b/tests/components/tibber/test_repairs.py @@ -36,13 +36,13 @@ async def test_repair_flow( # Assert the issue is present assert issue_registry.async_get_issue( domain="notify", - issue_id="migrate_notify_tibber", + issue_id=f"migrate_notify_tibber_{service}", ) assert len(issue_registry.issues) == 1 url = RepairsFlowIndexView.url resp = await http_client.post( - url, json={"handler": "notify", "issue_id": "migrate_notify_tibber"} + url, json={"handler": "notify", "issue_id": f"migrate_notify_tibber_{service}"} ) assert resp.status == HTTPStatus.OK data = await resp.json() @@ -61,6 +61,6 @@ async def test_repair_flow( # Assert the issue is no longer present assert not issue_registry.async_get_issue( domain="notify", - issue_id="migrate_notify_tibber", + issue_id=f"migrate_notify_tibber_{service}", ) assert len(issue_registry.issues) == 0