mirror of
https://github.com/home-assistant/core.git
synced 2025-07-22 20:57:21 +00:00
Repository event subscription (#67284)
This commit is contained in:
parent
73fdd47d54
commit
e65670fef4
@ -38,6 +38,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
)
|
||||
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
await coordinator.subscribe()
|
||||
|
||||
hass.data[DOMAIN][repository] = coordinator
|
||||
|
||||
@ -45,7 +46,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
|
||||
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
||||
entry.async_on_unload(entry.add_update_listener(async_reload_entry))
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@ -77,6 +77,10 @@ def async_cleanup_device_registry(
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||
"""Unload a config entry."""
|
||||
repositories: dict[str, GitHubDataUpdateCoordinator] = hass.data[DOMAIN]
|
||||
for coordinator in repositories.values():
|
||||
coordinator.unsubscribe()
|
||||
|
||||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
|
||||
hass.data.pop(DOMAIN)
|
||||
return unload_ok
|
||||
|
@ -11,7 +11,18 @@ DOMAIN = "github"
|
||||
CLIENT_ID = "1440cafcc86e3ea5d6a2"
|
||||
|
||||
DEFAULT_REPOSITORIES = ["home-assistant/core", "esphome/esphome"]
|
||||
DEFAULT_UPDATE_INTERVAL = timedelta(seconds=300)
|
||||
FALLBACK_UPDATE_INTERVAL = timedelta(hours=1, minutes=30)
|
||||
|
||||
CONF_ACCESS_TOKEN = "access_token"
|
||||
CONF_REPOSITORIES = "repositories"
|
||||
|
||||
|
||||
REFRESH_EVENT_TYPES = (
|
||||
"CreateEvent",
|
||||
"ForkEvent",
|
||||
"IssuesEvent",
|
||||
"PullRequestEvent",
|
||||
"PushEvent",
|
||||
"ReleaseEvent",
|
||||
"WatchEvent",
|
||||
)
|
||||
|
@ -6,15 +6,17 @@ from typing import Any
|
||||
from aiogithubapi import (
|
||||
GitHubAPI,
|
||||
GitHubConnectionException,
|
||||
GitHubEventModel,
|
||||
GitHubException,
|
||||
GitHubRatelimitException,
|
||||
GitHubResponseModel,
|
||||
)
|
||||
|
||||
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
||||
from .const import DEFAULT_UPDATE_INTERVAL, LOGGER
|
||||
from .const import FALLBACK_UPDATE_INTERVAL, LOGGER, REFRESH_EVENT_TYPES
|
||||
|
||||
GRAPHQL_REPOSITORY_QUERY = """
|
||||
query ($owner: String!, $repository: String!) {
|
||||
@ -109,13 +111,14 @@ class GitHubDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
self.repository = repository
|
||||
self._client = client
|
||||
self._last_response: GitHubResponseModel[dict[str, Any]] | None = None
|
||||
self._subscription_id: str | None = None
|
||||
self.data = {}
|
||||
|
||||
super().__init__(
|
||||
hass,
|
||||
LOGGER,
|
||||
name=repository,
|
||||
update_interval=DEFAULT_UPDATE_INTERVAL,
|
||||
update_interval=FALLBACK_UPDATE_INTERVAL,
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> GitHubResponseModel[dict[str, Any]]:
|
||||
@ -136,3 +139,26 @@ class GitHubDataUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
else:
|
||||
self._last_response = response
|
||||
return response.data["data"]["repository"]
|
||||
|
||||
async def _handle_event(self, event: GitHubEventModel) -> None:
|
||||
"""Handle an event."""
|
||||
if event.type in REFRESH_EVENT_TYPES:
|
||||
await self.async_request_refresh()
|
||||
|
||||
@staticmethod
|
||||
async def _handle_error(error: GitHubException) -> None:
|
||||
"""Handle an error."""
|
||||
LOGGER.error("An error occurred while processing new events - %s", error)
|
||||
|
||||
async def subscribe(self) -> None:
|
||||
"""Subscribe to repository events."""
|
||||
self._subscription_id = await self._client.repos.events.subscribe(
|
||||
self.repository,
|
||||
event_callback=self._handle_event,
|
||||
error_callback=self._handle_error,
|
||||
)
|
||||
self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, self.unsubscribe)
|
||||
|
||||
def unsubscribe(self, *args) -> None:
|
||||
"""Unsubscribe to repository events."""
|
||||
self._client.repos.events.unsubscribe(subscription_id=self._subscription_id)
|
||||
|
@ -31,6 +31,11 @@ async def setup_github_integration(
|
||||
},
|
||||
headers=headers,
|
||||
)
|
||||
aioclient_mock.get(
|
||||
f"https://api.github.com/repos/{repository}/events",
|
||||
json=[],
|
||||
headers=headers,
|
||||
)
|
||||
aioclient_mock.post(
|
||||
"https://api.github.com/graphql",
|
||||
json=json.loads(load_fixture("graphql.json", DOMAIN)),
|
||||
|
@ -1,10 +1,12 @@
|
||||
"""Test GitHub sensor."""
|
||||
import json
|
||||
|
||||
from homeassistant.components.github.const import DEFAULT_UPDATE_INTERVAL, DOMAIN
|
||||
from homeassistant.components.github.const import DOMAIN, FALLBACK_UPDATE_INTERVAL
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.util import dt
|
||||
|
||||
from .common import TEST_REPOSITORY
|
||||
|
||||
from tests.common import MockConfigEntry, async_fire_time_changed, load_fixture
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
@ -22,15 +24,21 @@ async def test_sensor_updates_with_empty_release_array(
|
||||
|
||||
response_json = json.loads(load_fixture("graphql.json", DOMAIN))
|
||||
response_json["data"]["repository"]["release"] = None
|
||||
headers = json.loads(load_fixture("base_headers.json", DOMAIN))
|
||||
|
||||
aioclient_mock.clear_requests()
|
||||
aioclient_mock.get(
|
||||
f"https://api.github.com/repos/{TEST_REPOSITORY}/events",
|
||||
json=[],
|
||||
headers=headers,
|
||||
)
|
||||
aioclient_mock.post(
|
||||
"https://api.github.com/graphql",
|
||||
json=response_json,
|
||||
headers=json.loads(load_fixture("base_headers.json", DOMAIN)),
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
async_fire_time_changed(hass, dt.utcnow() + DEFAULT_UPDATE_INTERVAL)
|
||||
async_fire_time_changed(hass, dt.utcnow() + FALLBACK_UPDATE_INTERVAL)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
new_state = hass.states.get(TEST_SENSOR_ENTITY)
|
||||
|
Loading…
x
Reference in New Issue
Block a user