Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ The client exposes the following resource modules:
| `client.api_keys` | API key management |
| `client.dependencies` | Service dependency tracking |
| `client.deploy_lock` | Deploy lock for safe deployments |
| `client.services` | Status Data catalog: vendor services, components, incidents, uptime |
| `client.status` | Dashboard overview |

## Pagination
Expand Down
9 changes: 9 additions & 0 deletions docs/openapi/monitoring-api.json
Original file line number Diff line number Diff line change
Expand Up @@ -13520,6 +13520,15 @@
"type": "boolean"
}
},
{
"name": "search",
"in": "query",
"description": "Case-insensitive substring match on service name or slug",
"required": false,
"schema": {
"type": "string"
}
},
{
"name": "cursor",
"in": "query",
Expand Down
34 changes: 34 additions & 0 deletions src/devhelm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
from devhelm.resources.notification_policies import NotificationPolicies
from devhelm.resources.resource_groups import ResourceGroups
from devhelm.resources.secrets import Secrets
from devhelm.resources.services import Services
from devhelm.resources.status import Status
from devhelm.resources.status_pages import StatusPages
from devhelm.resources.tags import Tags
Expand All @@ -46,8 +47,11 @@
ApiKeyDto,
AssertionSeverity,
AssertionTestResultDto,
BatchComponentUptimeDto,
CategoryDto,
CheckResultDto,
CheckTraceDto,
ComponentUptimeDayDto,
ConfirmationPolicyType,
CreateAlertChannelRequest,
CreateApiKeyRequest,
Expand All @@ -69,6 +73,7 @@
DashboardOverviewDto,
DeployLockDto,
EnvironmentDto,
GlobalStatusSummaryDto,
IncidentDetailDto,
IncidentDto,
IncidentNewStatus,
Expand All @@ -78,6 +83,7 @@
IncidentStatus,
IncidentTimelineDto,
IncidentUpdateCreatedBy,
LifecycleStatus,
LinkedIncidentStatus,
MaintenanceWindowDto,
MembershipStatus,
Expand All @@ -99,8 +105,18 @@
ResourceGroupHealthStatus,
ResourceGroupMemberDto,
RuleEvaluationDto,
ScheduledMaintenanceDto,
SecretDto,
ServiceCatalogDto,
ServiceComponentDto,
ServiceDayDetailDto,
ServiceDetailDto,
ServiceIncidentDetailDto,
ServiceIncidentDto,
ServiceLiveStatusDto,
ServiceSubscribeRequest,
ServiceSubscriptionDto,
ServiceUptimeResponse,
StatusPageBranding,
StatusPageComponentCurrentStatus,
StatusPageComponentDto,
Expand All @@ -124,6 +140,7 @@
TriggerRuleSeverity,
TriggerRuleType,
UpdateAlertChannelRequest,
UpdateAlertSensitivityRequest,
UpdateAssertionSeverity,
UpdateEnvironmentRequest,
UpdateMaintenanceWindowRequest,
Expand Down Expand Up @@ -184,6 +201,7 @@
"Dependencies",
"DeployLock",
"MaintenanceWindows",
"Services",
"Status",
"StatusPages",
# Response DTOs
Expand Down Expand Up @@ -216,6 +234,19 @@
"ApiKeyDto",
"ApiKeyCreateResponse",
"ServiceSubscriptionDto",
"ServiceCatalogDto",
"ServiceDetailDto",
"ServiceLiveStatusDto",
"ServiceComponentDto",
"ServiceIncidentDto",
"ServiceIncidentDetailDto",
"ServiceUptimeResponse",
"ServiceDayDetailDto",
"ScheduledMaintenanceDto",
"CategoryDto",
"GlobalStatusSummaryDto",
"BatchComponentUptimeDto",
"ComponentUptimeDayDto",
"MonitorVersionDto",
"CheckResultDto",
"DashboardOverviewDto",
Expand Down Expand Up @@ -261,6 +292,8 @@
"UpdateWebhookEndpointRequest",
"CreateApiKeyRequest",
"AcquireDeployLockRequest",
"ServiceSubscribeRequest",
"UpdateAlertSensitivityRequest",
# Enum aliases (descriptive names for codegen-numbered enums)
"AffectedComponentStatus",
"AlertDeliveryStatus",
Expand All @@ -272,6 +305,7 @@
"IncidentSeverity",
"IncidentStatus",
"IncidentUpdateCreatedBy",
"LifecycleStatus",
"LinkedIncidentStatus",
"MemberStatus",
"MembershipStatus",
Expand Down
13 changes: 11 additions & 2 deletions src/devhelm/_pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,18 @@ def fetch_cursor_page(
model_class: type[M],
cursor: str | None = None,
limit: int | None = None,
*,
extra_params: dict[str, Any] | None = None,
) -> CursorPage[M]:
"""Fetch a single page from a cursor-paginated endpoint with validation."""
params: dict[str, Any] = {}
"""Fetch a single page from a cursor-paginated endpoint with validation.

``extra_params`` is merged into the request so callers can forward
server-side filter kwargs (``category``, ``search``, …) alongside the
cursor controls. Pagination keys (``cursor``, ``limit``) always win
over user-supplied ``extra_params`` to keep the iterator's invariants
intact.
"""
params: dict[str, Any] = dict(extra_params) if extra_params else {}
if cursor:
params["cursor"] = cursor
if limit:
Expand Down
3 changes: 3 additions & 0 deletions src/devhelm/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from devhelm.resources.notification_policies import NotificationPolicies
from devhelm.resources.resource_groups import ResourceGroups
from devhelm.resources.secrets import Secrets
from devhelm.resources.services import Services
from devhelm.resources.status import Status
from devhelm.resources.status_pages import StatusPages
from devhelm.resources.tags import Tags
Expand Down Expand Up @@ -53,6 +54,7 @@ class Devhelm:
dependencies: Dependencies
deploy_lock: DeployLock
maintenance_windows: MaintenanceWindows
services: Services
status: Status
status_pages: StatusPages

Expand Down Expand Up @@ -99,5 +101,6 @@ def __init__(
self.dependencies = Dependencies(client)
self.deploy_lock = DeployLock(client)
self.maintenance_windows = MaintenanceWindows(client)
self.services = Services(client)
self.status = Status(client)
self.status_pages = StatusPages(client)
61 changes: 55 additions & 6 deletions src/devhelm/resources/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

import httpx

from devhelm._generated import ServiceSubscriptionDto
from devhelm._http import api_delete, api_get, api_post, path_param
from devhelm._generated import (
ServiceSubscribeRequest,
ServiceSubscriptionDto,
UpdateAlertSensitivityRequest,
)
from devhelm._http import api_delete, api_get, api_patch, api_post, path_param
from devhelm._pagination import Page, fetch_all_pages, fetch_page
from devhelm._validation import parse_single
from devhelm._validation import parse_single, validate_request


class Dependencies:
Expand Down Expand Up @@ -38,14 +42,59 @@ def get(self, id: int | str) -> ServiceSubscriptionDto:
f"GET /api/v1/service-subscriptions/{id}",
)

def track(self, slug: str) -> ServiceSubscriptionDto:
"""Track a new service dependency by slug."""
def track(
self,
slug: str,
*,
component_id: str | None = None,
alert_sensitivity: str | None = None,
) -> ServiceSubscriptionDto:
"""Track a new service dependency by slug.

``component_id`` subscribes to one component instead of the whole
service. ``alert_sensitivity`` is one of ``ALL``,
``INCIDENTS_ONLY``, ``MAJOR_ONLY``, or ``AWARENESS`` (the API
default — silent tracking with no alert fan-out). The request body
is omitted entirely when neither kwarg is provided.
"""
body: ServiceSubscribeRequest | None = None
if component_id is not None or alert_sensitivity is not None:
fields: dict[str, str] = {}
if component_id is not None:
fields["componentId"] = component_id
if alert_sensitivity is not None:
fields["alertSensitivity"] = alert_sensitivity
body = validate_request(
ServiceSubscribeRequest, fields, "dependencies.track"
)
return parse_single(
ServiceSubscriptionDto,
api_post(self._client, f"/api/v1/service-subscriptions/{path_param(slug)}"),
api_post(
self._client, f"/api/v1/service-subscriptions/{path_param(slug)}", body
),
f"POST /api/v1/service-subscriptions/{slug}",
)

def update_alert_sensitivity(
self, subscription_id: int | str, alert_sensitivity: str
) -> ServiceSubscriptionDto:
"""Update the alert sensitivity on a tracked dependency.

``alert_sensitivity`` is one of ``ALL``, ``INCIDENTS_ONLY``,
``MAJOR_ONLY``, or ``AWARENESS``.
"""
body = validate_request(
UpdateAlertSensitivityRequest,
{"alertSensitivity": alert_sensitivity},
"dependencies.update_alert_sensitivity",
)
path = f"/api/v1/service-subscriptions/{path_param(subscription_id)}"
return parse_single(
ServiceSubscriptionDto,
api_patch(self._client, f"{path}/alert-sensitivity", body),
f"PATCH /api/v1/service-subscriptions/{subscription_id}/alert-sensitivity",
)

def delete(self, id: int | str) -> None:
"""Remove a tracked dependency."""
api_delete(self._client, f"/api/v1/service-subscriptions/{path_param(id)}")
Loading
Loading