diff --git a/homeassistant/components/blueprint/importer.py b/homeassistant/components/blueprint/importer.py index 4517d134e69..c231a33991a 100644 --- a/homeassistant/components/blueprint/importer.py +++ b/homeassistant/components/blueprint/importer.py @@ -245,14 +245,36 @@ async def fetch_blueprint_from_website_url( return ImportedBlueprint(suggested_filename, raw_yaml, blueprint) +async def fetch_blueprint_from_generic_url( + hass: HomeAssistant, url: str +) -> ImportedBlueprint: + """Get a blueprint from a generic website.""" + session = aiohttp_client.async_get_clientsession(hass) + + resp = await session.get(url, raise_for_status=True) + raw_yaml = await resp.text() + data = yaml.parse_yaml(raw_yaml) + + assert isinstance(data, dict) + blueprint = Blueprint(data) + + parsed_import_url = yarl.URL(url) + suggested_filename = f"{parsed_import_url.host}/{parsed_import_url.parts[-1][:-5]}" + return ImportedBlueprint(suggested_filename, raw_yaml, blueprint) + + +FETCH_FUNCTIONS = ( + fetch_blueprint_from_community_post, + fetch_blueprint_from_github_url, + fetch_blueprint_from_github_gist_url, + fetch_blueprint_from_website_url, + fetch_blueprint_from_generic_url, +) + + async def fetch_blueprint_from_url(hass: HomeAssistant, url: str) -> ImportedBlueprint: """Get a blueprint from a url.""" - for func in ( - fetch_blueprint_from_community_post, - fetch_blueprint_from_github_url, - fetch_blueprint_from_github_gist_url, - fetch_blueprint_from_website_url, - ): + for func in FETCH_FUNCTIONS: with suppress(UnsupportedUrl): imported_bp = await func(hass, url) imported_bp.blueprint.update_metadata(source_url=url) diff --git a/tests/components/blueprint/test_importer.py b/tests/components/blueprint/test_importer.py index f135bbf23b8..94036d208ab 100644 --- a/tests/components/blueprint/test_importer.py +++ b/tests/components/blueprint/test_importer.py @@ -192,9 +192,28 @@ async def test_fetch_blueprint_from_website_url( assert imported_blueprint.blueprint.metadata["source_url"] == url -async def test_fetch_blueprint_from_unsupported_url(hass: HomeAssistant) -> None: - """Test fetching blueprint from an unsupported URL.""" - url = "https://example.com/unsupported.yaml" +async def test_fetch_blueprint_from_generic_url( + hass: HomeAssistant, aioclient_mock: AiohttpClientMocker +) -> None: + """Test fetching blueprint from url.""" + aioclient_mock.get( + "https://example.org/path/someblueprint.yaml", + text=Path( + hass.config.path("blueprints/automation/test_event_service.yaml") + ).read_text(encoding="utf8"), + ) - with pytest.raises(HomeAssistantError, match=r"^Unsupported URL$"): - await importer.fetch_blueprint_from_url(hass, url) + url = "https://example.org/path/someblueprint.yaml" + imported_blueprint = await importer.fetch_blueprint_from_url(hass, url) + assert isinstance(imported_blueprint, importer.ImportedBlueprint) + assert imported_blueprint.blueprint.domain == "automation" + assert imported_blueprint.suggested_filename == "example.org/someblueprint" + assert imported_blueprint.blueprint.metadata["source_url"] == url + + +def test_generic_importer_last() -> None: + """Test that generic importer is always the last one.""" + assert ( + importer.FETCH_FUNCTIONS.count(importer.fetch_blueprint_from_generic_url) == 1 + ) + assert importer.FETCH_FUNCTIONS[-1] == importer.fetch_blueprint_from_generic_url