Add repairs from issue registry to integration diagnostics (#148498)

This commit is contained in:
G Johansson 2025-07-09 19:52:16 +02:00 committed by GitHub
parent 3045f67ae5
commit 57083d877e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 73 additions and 3 deletions

View File

@ -19,6 +19,7 @@ from homeassistant.helpers import (
config_validation as cv, config_validation as cv,
device_registry as dr, device_registry as dr,
integration_platform, integration_platform,
issue_registry as ir,
) )
from homeassistant.helpers.device_registry import DeviceEntry from homeassistant.helpers.device_registry import DeviceEntry
from homeassistant.helpers.json import ( from homeassistant.helpers.json import (
@ -187,6 +188,7 @@ def async_format_manifest(manifest: Manifest) -> Manifest:
async def _async_get_json_file_response( async def _async_get_json_file_response(
hass: HomeAssistant, hass: HomeAssistant,
data: Mapping[str, Any], data: Mapping[str, Any],
data_issues: list[dict[str, Any]] | None,
filename: str, filename: str,
domain: str, domain: str,
d_id: str, d_id: str,
@ -213,6 +215,8 @@ async def _async_get_json_file_response(
"setup_times": async_get_domain_setup_times(hass, domain), "setup_times": async_get_domain_setup_times(hass, domain),
"data": data, "data": data,
} }
if data_issues is not None:
payload["issues"] = data_issues
try: try:
json_data = json.dumps(payload, indent=2, cls=ExtendedJSONEncoder) json_data = json.dumps(payload, indent=2, cls=ExtendedJSONEncoder)
except TypeError: except TypeError:
@ -275,6 +279,14 @@ class DownloadDiagnosticsView(http.HomeAssistantView):
filename = f"{config_entry.domain}-{config_entry.entry_id}" filename = f"{config_entry.domain}-{config_entry.entry_id}"
issue_registry = ir.async_get(hass)
issues = issue_registry.issues
data_issues = [
issue_reg.to_json()
for issue_id, issue_reg in issues.items()
if issue_id[0] == config_entry.domain
]
if not device_diagnostics: if not device_diagnostics:
# Config entry diagnostics # Config entry diagnostics
if info.config_entry_diagnostics is None: if info.config_entry_diagnostics is None:
@ -282,7 +294,7 @@ class DownloadDiagnosticsView(http.HomeAssistantView):
data = await info.config_entry_diagnostics(hass, config_entry) data = await info.config_entry_diagnostics(hass, config_entry)
filename = f"{DiagnosticsType.CONFIG_ENTRY}-{filename}" filename = f"{DiagnosticsType.CONFIG_ENTRY}-{filename}"
return await _async_get_json_file_response( return await _async_get_json_file_response(
hass, data, filename, config_entry.domain, d_id hass, data, data_issues, filename, config_entry.domain, d_id
) )
# Device diagnostics # Device diagnostics
@ -300,5 +312,5 @@ class DownloadDiagnosticsView(http.HomeAssistantView):
data = await info.device_diagnostics(hass, config_entry, device) data = await info.device_diagnostics(hass, config_entry, device)
return await _async_get_json_file_response( return await _async_get_json_file_response(
hass, data, filename, config_entry.domain, d_id, sub_id hass, data, data_issues, filename, config_entry.domain, d_id, sub_id
) )

View File

@ -1,13 +1,15 @@
"""Test the Diagnostics integration.""" """Test the Diagnostics integration."""
from datetime import datetime
from http import HTTPStatus from http import HTTPStatus
from unittest.mock import AsyncMock, Mock, patch from unittest.mock import AsyncMock, Mock, patch
from freezegun import freeze_time
import pytest import pytest
from homeassistant.components.websocket_api import TYPE_RESULT from homeassistant.components.websocket_api import TYPE_RESULT
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr from homeassistant.helpers import device_registry as dr, issue_registry as ir
from homeassistant.helpers.system_info import async_get_system_info from homeassistant.helpers.system_info import async_get_system_info
from homeassistant.loader import async_get_integration from homeassistant.loader import async_get_integration
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
@ -81,10 +83,20 @@ async def test_websocket(
@pytest.mark.usefixtures("enable_custom_integrations") @pytest.mark.usefixtures("enable_custom_integrations")
@pytest.mark.parametrize(
"ignore_missing_translations",
[
[
"component.fake_integration.issues.test_issue.title",
"component.fake_integration.issues.test_issue.description",
]
],
)
async def test_download_diagnostics( async def test_download_diagnostics(
hass: HomeAssistant, hass: HomeAssistant,
hass_client: ClientSessionGenerator, hass_client: ClientSessionGenerator,
device_registry: dr.DeviceRegistry, device_registry: dr.DeviceRegistry,
issue_registry: ir.IssueRegistry,
) -> None: ) -> None:
"""Test download diagnostics.""" """Test download diagnostics."""
config_entry = MockConfigEntry(domain="fake_integration") config_entry = MockConfigEntry(domain="fake_integration")
@ -95,6 +107,18 @@ async def test_download_diagnostics(
integration = await async_get_integration(hass, "fake_integration") integration = await async_get_integration(hass, "fake_integration")
original_manifest = integration.manifest.copy() original_manifest = integration.manifest.copy()
original_manifest["codeowners"] = ["@test"] original_manifest["codeowners"] = ["@test"]
with freeze_time(datetime(2025, 7, 9, 14, 00, 00)):
issue_registry.async_get_or_create(
domain="fake_integration",
issue_id="test_issue",
breaks_in_ha_version="2023.10.0",
severity=ir.IssueSeverity.WARNING,
is_fixable=False,
is_persistent=True,
translation_key="test_issue",
)
with patch.object(integration, "manifest", original_manifest): with patch.object(integration, "manifest", original_manifest):
response = await _get_diagnostics_for_config_entry( response = await _get_diagnostics_for_config_entry(
hass, hass_client, config_entry hass, hass_client, config_entry
@ -179,6 +203,23 @@ async def test_download_diagnostics(
"requirements": [], "requirements": [],
}, },
"data": {"config_entry": "info"}, "data": {"config_entry": "info"},
"issues": [
{
"breaks_in_ha_version": "2023.10.0",
"created": "2025-07-09T14:00:00+00:00",
"data": None,
"dismissed_version": None,
"domain": "fake_integration",
"is_fixable": False,
"is_persistent": True,
"issue_domain": None,
"issue_id": "test_issue",
"learn_more_url": None,
"severity": "warning",
"translation_key": "test_issue",
"translation_placeholders": None,
},
],
} }
device = device_registry.async_get_or_create( device = device_registry.async_get_or_create(
@ -266,6 +307,23 @@ async def test_download_diagnostics(
"requirements": [], "requirements": [],
}, },
"data": {"device": "info"}, "data": {"device": "info"},
"issues": [
{
"breaks_in_ha_version": "2023.10.0",
"created": "2025-07-09T14:00:00+00:00",
"data": None,
"dismissed_version": None,
"domain": "fake_integration",
"is_fixable": False,
"is_persistent": True,
"issue_domain": None,
"issue_id": "test_issue",
"learn_more_url": None,
"severity": "warning",
"translation_key": "test_issue",
"translation_placeholders": None,
},
],
"setup_times": {}, "setup_times": {},
} }