dominus-sdk-python 6.2.0__tar.gz → 6.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/PKG-INFO +1 -1
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/__init__.py +15 -1
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/errors.py +41 -1
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/stash.py +160 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus_sdk_python.egg-info/PKG-INFO +1 -1
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus_sdk_python.egg-info/SOURCES.txt +1 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/pyproject.toml +1 -1
- dominus_sdk_python-6.3.0/tests/test_stash_artifact_facade.py +355 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/README.md +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/config/__init__.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/config/endpoints.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/helpers/__init__.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/helpers/auth.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/helpers/cache.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/helpers/console_capture.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/helpers/core.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/helpers/crypto.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/helpers/sse.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/helpers/trace.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/__init__.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/admin.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/ai.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/artifacts.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/auth.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/authority.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/browser.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/coder.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/courier.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/db.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/ddl.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/deployer.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/fastapi.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/files.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/health.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/jobs.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/logs.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/platform.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/portal.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/processor.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/publisher.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/recipes.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/redis.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/secrets.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/secure.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/sync.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/warden.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/namespaces/workflow.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/services/__init__.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus/start.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus_sdk_python.egg-info/dependency_links.txt +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus_sdk_python.egg-info/requires.txt +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus_sdk_python.egg-info/top_level.txt +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/setup.cfg +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_auth.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_authority_public_vocabulary.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_browser_namespace.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_control_plane_namespaces.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_errors.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_flat_commands.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_health.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_logs.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_platform_coder_namespaces.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_provisioning_parity.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_public_exports.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_publisher_namespace.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_recipes_namespace.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_recipes_stash_routing.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_transport_compat.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_workflow_lifecycle.py +0 -0
- {dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_workflow_refs.py +0 -0
|
@@ -160,12 +160,19 @@ from .errors import (
|
|
|
160
160
|
ValidationError,
|
|
161
161
|
ConflictError,
|
|
162
162
|
ServiceError,
|
|
163
|
+
StashBookmarkArtifactNotFound,
|
|
164
|
+
StashBookmarkInvalidVersionRef,
|
|
165
|
+
StashBookmarkDuplicateName,
|
|
166
|
+
StashBookmarkUpstreamRejected,
|
|
167
|
+
StashWatchInvalidWebhookUrl,
|
|
168
|
+
StashWatchUpstreamRejected,
|
|
169
|
+
StashWatchNotFound,
|
|
163
170
|
SecureTableError,
|
|
164
171
|
ConnectionError as DominusConnectionError,
|
|
165
172
|
TimeoutError as DominusTimeoutError,
|
|
166
173
|
)
|
|
167
174
|
|
|
168
|
-
__version__ = "6.
|
|
175
|
+
__version__ = "6.3.0"
|
|
169
176
|
__all__ = [
|
|
170
177
|
# Main SDK instance
|
|
171
178
|
"dominus",
|
|
@@ -250,6 +257,13 @@ __all__ = [
|
|
|
250
257
|
"ValidationError",
|
|
251
258
|
"ConflictError",
|
|
252
259
|
"ServiceError",
|
|
260
|
+
"StashBookmarkArtifactNotFound",
|
|
261
|
+
"StashBookmarkInvalidVersionRef",
|
|
262
|
+
"StashBookmarkDuplicateName",
|
|
263
|
+
"StashBookmarkUpstreamRejected",
|
|
264
|
+
"StashWatchInvalidWebhookUrl",
|
|
265
|
+
"StashWatchUpstreamRejected",
|
|
266
|
+
"StashWatchNotFound",
|
|
253
267
|
"SecureTableError",
|
|
254
268
|
"DominusConnectionError",
|
|
255
269
|
"DominusTimeoutError",
|
|
@@ -205,6 +205,34 @@ class ServiceError(DominusError):
|
|
|
205
205
|
super().__init__(message, status_code, details, endpoint)
|
|
206
206
|
|
|
207
207
|
|
|
208
|
+
class StashBookmarkArtifactNotFound(NotFoundError):
|
|
209
|
+
"""Raised when a stash artifact bookmark target cannot be found."""
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class StashBookmarkInvalidVersionRef(ValidationError):
|
|
213
|
+
"""Raised when a stash artifact bookmark version_ref is invalid."""
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class StashBookmarkDuplicateName(ConflictError):
|
|
217
|
+
"""Raised when a stash artifact bookmark name is already in use."""
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class StashBookmarkUpstreamRejected(ServiceError):
|
|
221
|
+
"""Raised when the artifact backend rejects a stash bookmark operation."""
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class StashWatchInvalidWebhookUrl(ValidationError):
|
|
225
|
+
"""Raised when a stash artifact watcher webhook_url is invalid."""
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class StashWatchUpstreamRejected(ServiceError):
|
|
229
|
+
"""Raised when the artifact backend rejects a stash watch operation."""
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
class StashWatchNotFound(NotFoundError):
|
|
233
|
+
"""Raised when a stash artifact watcher cannot be found."""
|
|
234
|
+
|
|
235
|
+
|
|
208
236
|
class ConnectionError(DominusError):
|
|
209
237
|
"""Raised when connection to the backend fails."""
|
|
210
238
|
|
|
@@ -244,6 +272,17 @@ class SecureTableError(DominusError):
|
|
|
244
272
|
super().__init__(message, status_code, details, endpoint)
|
|
245
273
|
|
|
246
274
|
|
|
275
|
+
STASH_ERROR_CLASSES = {
|
|
276
|
+
"stash.bookmark.artifact_not_found": StashBookmarkArtifactNotFound,
|
|
277
|
+
"stash.bookmark.invalid_version_ref": StashBookmarkInvalidVersionRef,
|
|
278
|
+
"stash.bookmark.duplicate_name": StashBookmarkDuplicateName,
|
|
279
|
+
"stash.bookmark.upstream_rejected": StashBookmarkUpstreamRejected,
|
|
280
|
+
"stash.watch.invalid_webhook_url": StashWatchInvalidWebhookUrl,
|
|
281
|
+
"stash.watch.upstream_rejected": StashWatchUpstreamRejected,
|
|
282
|
+
"stash.watch.not_found": StashWatchNotFound,
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
|
|
247
286
|
def raise_for_status(
|
|
248
287
|
status_code: int,
|
|
249
288
|
message: str,
|
|
@@ -262,6 +301,7 @@ def raise_for_status(
|
|
|
262
301
|
Raises:
|
|
263
302
|
Appropriate DominusError subclass
|
|
264
303
|
"""
|
|
304
|
+
code = _first_string((details or {}).get("code"))
|
|
265
305
|
error_classes = {
|
|
266
306
|
400: ValidationError,
|
|
267
307
|
401: AuthenticationError,
|
|
@@ -274,5 +314,5 @@ def raise_for_status(
|
|
|
274
314
|
504: TimeoutError,
|
|
275
315
|
}
|
|
276
316
|
|
|
277
|
-
error_class = error_classes.get(status_code, DominusError)
|
|
317
|
+
error_class = STASH_ERROR_CLASSES.get(code) or error_classes.get(status_code, DominusError)
|
|
278
318
|
raise error_class(message, status_code, details, endpoint)
|
|
@@ -6,10 +6,18 @@ stores items in each project's ``stash.*`` schema and transparently falls
|
|
|
6
6
|
back to a designated shared project on read.
|
|
7
7
|
"""
|
|
8
8
|
from typing import Any, Dict, List, Optional, TYPE_CHECKING
|
|
9
|
+
from urllib.parse import urlencode
|
|
9
10
|
|
|
10
11
|
if TYPE_CHECKING:
|
|
11
12
|
from ..start import Dominus
|
|
12
13
|
|
|
14
|
+
BookmarkRef = Dict[str, Any]
|
|
15
|
+
WatcherRef = Dict[str, Any]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _facade_query(*, env: str, kind: str, scope: str, key: str) -> str:
|
|
19
|
+
return urlencode({"env": env, "kind": kind, "scope": scope, "key": key})
|
|
20
|
+
|
|
13
21
|
|
|
14
22
|
class StashNamespace:
|
|
15
23
|
"""
|
|
@@ -273,3 +281,155 @@ class StashNamespace:
|
|
|
273
281
|
body=body,
|
|
274
282
|
use_gateway=True,
|
|
275
283
|
)
|
|
284
|
+
|
|
285
|
+
async def bookmark(
|
|
286
|
+
self,
|
|
287
|
+
*,
|
|
288
|
+
env: str,
|
|
289
|
+
kind: str,
|
|
290
|
+
scope: str,
|
|
291
|
+
key: str,
|
|
292
|
+
name: str,
|
|
293
|
+
version_ref: str,
|
|
294
|
+
timeout: float = 30.0,
|
|
295
|
+
) -> BookmarkRef:
|
|
296
|
+
"""Create or update a named bookmark for a stash artifact facade item."""
|
|
297
|
+
return await self._client._request(
|
|
298
|
+
endpoint="/svc/stash/bookmark",
|
|
299
|
+
method="POST",
|
|
300
|
+
body={
|
|
301
|
+
"env": env,
|
|
302
|
+
"kind": kind,
|
|
303
|
+
"scope": scope,
|
|
304
|
+
"key": key,
|
|
305
|
+
"name": name,
|
|
306
|
+
"version_ref": version_ref,
|
|
307
|
+
},
|
|
308
|
+
use_gateway=True,
|
|
309
|
+
timeout=timeout,
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
async def unbookmark(
|
|
313
|
+
self,
|
|
314
|
+
*,
|
|
315
|
+
env: str,
|
|
316
|
+
kind: str,
|
|
317
|
+
scope: str,
|
|
318
|
+
key: str,
|
|
319
|
+
name: str,
|
|
320
|
+
timeout: float = 30.0,
|
|
321
|
+
) -> None:
|
|
322
|
+
"""Remove a named bookmark from a stash artifact facade item."""
|
|
323
|
+
await self._client._request(
|
|
324
|
+
endpoint="/svc/stash/unbookmark",
|
|
325
|
+
method="POST",
|
|
326
|
+
body={
|
|
327
|
+
"env": env,
|
|
328
|
+
"kind": kind,
|
|
329
|
+
"scope": scope,
|
|
330
|
+
"key": key,
|
|
331
|
+
"name": name,
|
|
332
|
+
},
|
|
333
|
+
use_gateway=True,
|
|
334
|
+
timeout=timeout,
|
|
335
|
+
)
|
|
336
|
+
return None
|
|
337
|
+
|
|
338
|
+
async def watch(
|
|
339
|
+
self,
|
|
340
|
+
*,
|
|
341
|
+
env: str,
|
|
342
|
+
kind: str,
|
|
343
|
+
scope: str,
|
|
344
|
+
key: str,
|
|
345
|
+
watcher_name: str,
|
|
346
|
+
webhook_url: str,
|
|
347
|
+
timeout: float = 30.0,
|
|
348
|
+
) -> WatcherRef:
|
|
349
|
+
"""Create or update a webhook watcher for a stash artifact facade item."""
|
|
350
|
+
return await self._client._request(
|
|
351
|
+
endpoint="/svc/stash/watch",
|
|
352
|
+
method="POST",
|
|
353
|
+
body={
|
|
354
|
+
"env": env,
|
|
355
|
+
"kind": kind,
|
|
356
|
+
"scope": scope,
|
|
357
|
+
"key": key,
|
|
358
|
+
"watcher_name": watcher_name,
|
|
359
|
+
"webhook_url": webhook_url,
|
|
360
|
+
},
|
|
361
|
+
use_gateway=True,
|
|
362
|
+
timeout=timeout,
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
async def unwatch(
|
|
366
|
+
self,
|
|
367
|
+
*,
|
|
368
|
+
env: str,
|
|
369
|
+
kind: str,
|
|
370
|
+
scope: str,
|
|
371
|
+
key: str,
|
|
372
|
+
watcher_name: str,
|
|
373
|
+
timeout: float = 30.0,
|
|
374
|
+
) -> None:
|
|
375
|
+
"""Remove a webhook watcher from a stash artifact facade item."""
|
|
376
|
+
await self._client._request(
|
|
377
|
+
endpoint="/svc/stash/unwatch",
|
|
378
|
+
method="POST",
|
|
379
|
+
body={
|
|
380
|
+
"env": env,
|
|
381
|
+
"kind": kind,
|
|
382
|
+
"scope": scope,
|
|
383
|
+
"key": key,
|
|
384
|
+
"watcher_name": watcher_name,
|
|
385
|
+
},
|
|
386
|
+
use_gateway=True,
|
|
387
|
+
timeout=timeout,
|
|
388
|
+
)
|
|
389
|
+
return None
|
|
390
|
+
|
|
391
|
+
async def list_bookmarks(
|
|
392
|
+
self,
|
|
393
|
+
*,
|
|
394
|
+
env: str,
|
|
395
|
+
kind: str,
|
|
396
|
+
scope: str,
|
|
397
|
+
key: str,
|
|
398
|
+
timeout: float = 30.0,
|
|
399
|
+
) -> List[BookmarkRef]:
|
|
400
|
+
"""List bookmark refs for a stash artifact facade item."""
|
|
401
|
+
result = await self._client._request(
|
|
402
|
+
endpoint=f"/svc/stash/bookmark/list?{_facade_query(env=env, kind=kind, scope=scope, key=key)}",
|
|
403
|
+
method="GET",
|
|
404
|
+
use_gateway=True,
|
|
405
|
+
timeout=timeout,
|
|
406
|
+
)
|
|
407
|
+
if isinstance(result, list):
|
|
408
|
+
return result
|
|
409
|
+
if isinstance(result, dict):
|
|
410
|
+
bookmarks = result.get("bookmarks")
|
|
411
|
+
return bookmarks if isinstance(bookmarks, list) else []
|
|
412
|
+
return []
|
|
413
|
+
|
|
414
|
+
async def list_watchers(
|
|
415
|
+
self,
|
|
416
|
+
*,
|
|
417
|
+
env: str,
|
|
418
|
+
kind: str,
|
|
419
|
+
scope: str,
|
|
420
|
+
key: str,
|
|
421
|
+
timeout: float = 30.0,
|
|
422
|
+
) -> List[WatcherRef]:
|
|
423
|
+
"""List watcher refs for a stash artifact facade item."""
|
|
424
|
+
result = await self._client._request(
|
|
425
|
+
endpoint=f"/svc/stash/watch/list?{_facade_query(env=env, kind=kind, scope=scope, key=key)}",
|
|
426
|
+
method="GET",
|
|
427
|
+
use_gateway=True,
|
|
428
|
+
timeout=timeout,
|
|
429
|
+
)
|
|
430
|
+
if isinstance(result, list):
|
|
431
|
+
return result
|
|
432
|
+
if isinstance(result, dict):
|
|
433
|
+
watchers = result.get("watchers")
|
|
434
|
+
return watchers if isinstance(watchers, list) else []
|
|
435
|
+
return []
|
{dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus_sdk_python.egg-info/SOURCES.txt
RENAMED
|
@@ -62,6 +62,7 @@ tests/test_public_exports.py
|
|
|
62
62
|
tests/test_publisher_namespace.py
|
|
63
63
|
tests/test_recipes_namespace.py
|
|
64
64
|
tests/test_recipes_stash_routing.py
|
|
65
|
+
tests/test_stash_artifact_facade.py
|
|
65
66
|
tests/test_transport_compat.py
|
|
66
67
|
tests/test_workflow_lifecycle.py
|
|
67
68
|
tests/test_workflow_refs.py
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
import dominus.start as start_module
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@pytest.fixture()
|
|
7
|
+
def sdk(monkeypatch):
|
|
8
|
+
monkeypatch.setattr(start_module, "_VALIDATION_ERROR", None)
|
|
9
|
+
monkeypatch.setattr(start_module, "_TOKEN", "a" * 64)
|
|
10
|
+
monkeypatch.setattr(start_module, "_VALIDATED", False)
|
|
11
|
+
monkeypatch.setattr(start_module, "_BASE_URL", "https://gateway.example")
|
|
12
|
+
monkeypatch.setattr(start_module, "_GATEWAY_URL", "https://gateway.example")
|
|
13
|
+
return start_module.Dominus()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@pytest.mark.asyncio
|
|
17
|
+
async def test_bookmark_posts_to_stash_facade(monkeypatch, sdk):
|
|
18
|
+
calls = []
|
|
19
|
+
|
|
20
|
+
async def fake_request(**kwargs):
|
|
21
|
+
calls.append(kwargs)
|
|
22
|
+
return {
|
|
23
|
+
"name": "latest",
|
|
24
|
+
"version_ref": "v3",
|
|
25
|
+
"version": 3,
|
|
26
|
+
"hash": "sha256:bookmark",
|
|
27
|
+
"sticky_retention": None,
|
|
28
|
+
"ttl_seconds": None,
|
|
29
|
+
"expires_at": None,
|
|
30
|
+
"changed_since_bookmark": False,
|
|
31
|
+
"content_available": True,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
35
|
+
|
|
36
|
+
result = await sdk.stash.bookmark(
|
|
37
|
+
env="production",
|
|
38
|
+
kind="artifact",
|
|
39
|
+
scope="self",
|
|
40
|
+
key="my-key",
|
|
41
|
+
name="latest",
|
|
42
|
+
version_ref="v3",
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
assert result == {
|
|
46
|
+
"name": "latest",
|
|
47
|
+
"version_ref": "v3",
|
|
48
|
+
"version": 3,
|
|
49
|
+
"hash": "sha256:bookmark",
|
|
50
|
+
"sticky_retention": None,
|
|
51
|
+
"ttl_seconds": None,
|
|
52
|
+
"expires_at": None,
|
|
53
|
+
"changed_since_bookmark": False,
|
|
54
|
+
"content_available": True,
|
|
55
|
+
}
|
|
56
|
+
assert calls == [
|
|
57
|
+
{
|
|
58
|
+
"endpoint": "/svc/stash/bookmark",
|
|
59
|
+
"method": "POST",
|
|
60
|
+
"body": {
|
|
61
|
+
"env": "production",
|
|
62
|
+
"kind": "artifact",
|
|
63
|
+
"scope": "self",
|
|
64
|
+
"key": "my-key",
|
|
65
|
+
"name": "latest",
|
|
66
|
+
"version_ref": "v3",
|
|
67
|
+
},
|
|
68
|
+
"use_gateway": True,
|
|
69
|
+
"timeout": 30.0,
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@pytest.mark.asyncio
|
|
75
|
+
async def test_unbookmark_posts_to_stash_facade(monkeypatch, sdk):
|
|
76
|
+
calls = []
|
|
77
|
+
|
|
78
|
+
async def fake_request(**kwargs):
|
|
79
|
+
calls.append(kwargs)
|
|
80
|
+
return {"deleted": True}
|
|
81
|
+
|
|
82
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
83
|
+
|
|
84
|
+
result = await sdk.stash.unbookmark(
|
|
85
|
+
env="production",
|
|
86
|
+
kind="artifact",
|
|
87
|
+
scope="self",
|
|
88
|
+
key="my-key",
|
|
89
|
+
name="latest",
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
assert result is None
|
|
93
|
+
assert calls == [
|
|
94
|
+
{
|
|
95
|
+
"endpoint": "/svc/stash/unbookmark",
|
|
96
|
+
"method": "POST",
|
|
97
|
+
"body": {
|
|
98
|
+
"env": "production",
|
|
99
|
+
"kind": "artifact",
|
|
100
|
+
"scope": "self",
|
|
101
|
+
"key": "my-key",
|
|
102
|
+
"name": "latest",
|
|
103
|
+
},
|
|
104
|
+
"use_gateway": True,
|
|
105
|
+
"timeout": 30.0,
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@pytest.mark.asyncio
|
|
111
|
+
async def test_watch_posts_to_stash_facade(monkeypatch, sdk):
|
|
112
|
+
calls = []
|
|
113
|
+
|
|
114
|
+
async def fake_request(**kwargs):
|
|
115
|
+
calls.append(kwargs)
|
|
116
|
+
return {
|
|
117
|
+
"watcher_name": "notify-reader",
|
|
118
|
+
"webhook_url": "https://hooks.example/stash",
|
|
119
|
+
"status": "active",
|
|
120
|
+
"created_at": "2026-06-26T12:00:00Z",
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
124
|
+
|
|
125
|
+
result = await sdk.stash.watch(
|
|
126
|
+
env="production",
|
|
127
|
+
kind="artifact",
|
|
128
|
+
scope="self",
|
|
129
|
+
key="my-key",
|
|
130
|
+
watcher_name="notify-reader",
|
|
131
|
+
webhook_url="https://hooks.example/stash",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
assert result == {
|
|
135
|
+
"watcher_name": "notify-reader",
|
|
136
|
+
"webhook_url": "https://hooks.example/stash",
|
|
137
|
+
"status": "active",
|
|
138
|
+
"created_at": "2026-06-26T12:00:00Z",
|
|
139
|
+
}
|
|
140
|
+
assert calls == [
|
|
141
|
+
{
|
|
142
|
+
"endpoint": "/svc/stash/watch",
|
|
143
|
+
"method": "POST",
|
|
144
|
+
"body": {
|
|
145
|
+
"env": "production",
|
|
146
|
+
"kind": "artifact",
|
|
147
|
+
"scope": "self",
|
|
148
|
+
"key": "my-key",
|
|
149
|
+
"watcher_name": "notify-reader",
|
|
150
|
+
"webhook_url": "https://hooks.example/stash",
|
|
151
|
+
},
|
|
152
|
+
"use_gateway": True,
|
|
153
|
+
"timeout": 30.0,
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@pytest.mark.asyncio
|
|
159
|
+
async def test_unwatch_posts_to_stash_facade(monkeypatch, sdk):
|
|
160
|
+
calls = []
|
|
161
|
+
|
|
162
|
+
async def fake_request(**kwargs):
|
|
163
|
+
calls.append(kwargs)
|
|
164
|
+
return {"deleted": True}
|
|
165
|
+
|
|
166
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
167
|
+
|
|
168
|
+
result = await sdk.stash.unwatch(
|
|
169
|
+
env="production",
|
|
170
|
+
kind="artifact",
|
|
171
|
+
scope="self",
|
|
172
|
+
key="my-key",
|
|
173
|
+
watcher_name="notify-reader",
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
assert result is None
|
|
177
|
+
assert calls == [
|
|
178
|
+
{
|
|
179
|
+
"endpoint": "/svc/stash/unwatch",
|
|
180
|
+
"method": "POST",
|
|
181
|
+
"body": {
|
|
182
|
+
"env": "production",
|
|
183
|
+
"kind": "artifact",
|
|
184
|
+
"scope": "self",
|
|
185
|
+
"key": "my-key",
|
|
186
|
+
"watcher_name": "notify-reader",
|
|
187
|
+
},
|
|
188
|
+
"use_gateway": True,
|
|
189
|
+
"timeout": 30.0,
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@pytest.mark.asyncio
|
|
195
|
+
async def test_list_bookmarks_gets_stash_facade(monkeypatch, sdk):
|
|
196
|
+
calls = []
|
|
197
|
+
bookmarks = [
|
|
198
|
+
{
|
|
199
|
+
"name": "latest",
|
|
200
|
+
"version_ref": "v3",
|
|
201
|
+
"version": 3,
|
|
202
|
+
"hash": "sha256:bookmark",
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
async def fake_request(**kwargs):
|
|
207
|
+
calls.append(kwargs)
|
|
208
|
+
return bookmarks
|
|
209
|
+
|
|
210
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
211
|
+
|
|
212
|
+
result = await sdk.stash.list_bookmarks(
|
|
213
|
+
env="production",
|
|
214
|
+
kind="artifact",
|
|
215
|
+
scope="self",
|
|
216
|
+
key="my-key",
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
assert result == bookmarks
|
|
220
|
+
assert calls == [
|
|
221
|
+
{
|
|
222
|
+
"endpoint": "/svc/stash/bookmark/list?env=production&kind=artifact&scope=self&key=my-key",
|
|
223
|
+
"method": "GET",
|
|
224
|
+
"use_gateway": True,
|
|
225
|
+
"timeout": 30.0,
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@pytest.mark.asyncio
|
|
231
|
+
async def test_list_watchers_gets_stash_facade(monkeypatch, sdk):
|
|
232
|
+
calls = []
|
|
233
|
+
watchers = [
|
|
234
|
+
{
|
|
235
|
+
"watcher_name": "notify-reader",
|
|
236
|
+
"webhook_url": "https://hooks.example/stash",
|
|
237
|
+
"status": "active",
|
|
238
|
+
}
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
async def fake_request(**kwargs):
|
|
242
|
+
calls.append(kwargs)
|
|
243
|
+
return watchers
|
|
244
|
+
|
|
245
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
246
|
+
|
|
247
|
+
result = await sdk.stash.list_watchers(
|
|
248
|
+
env="production",
|
|
249
|
+
kind="artifact",
|
|
250
|
+
scope="self",
|
|
251
|
+
key="my-key",
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
assert result == watchers
|
|
255
|
+
assert calls == [
|
|
256
|
+
{
|
|
257
|
+
"endpoint": "/svc/stash/watch/list?env=production&kind=artifact&scope=self&key=my-key",
|
|
258
|
+
"method": "GET",
|
|
259
|
+
"use_gateway": True,
|
|
260
|
+
"timeout": 30.0,
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def test_stash_facade_error_codes_map_to_public_exceptions():
|
|
266
|
+
from dominus import (
|
|
267
|
+
StashBookmarkArtifactNotFound,
|
|
268
|
+
StashBookmarkDuplicateName,
|
|
269
|
+
StashBookmarkInvalidVersionRef,
|
|
270
|
+
StashBookmarkUpstreamRejected,
|
|
271
|
+
StashWatchInvalidWebhookUrl,
|
|
272
|
+
StashWatchNotFound,
|
|
273
|
+
StashWatchUpstreamRejected,
|
|
274
|
+
)
|
|
275
|
+
from dominus.errors import raise_for_status
|
|
276
|
+
|
|
277
|
+
cases = [
|
|
278
|
+
(404, "stash.bookmark.artifact_not_found", StashBookmarkArtifactNotFound),
|
|
279
|
+
(400, "stash.bookmark.invalid_version_ref", StashBookmarkInvalidVersionRef),
|
|
280
|
+
(409, "stash.bookmark.duplicate_name", StashBookmarkDuplicateName),
|
|
281
|
+
(502, "stash.bookmark.upstream_rejected", StashBookmarkUpstreamRejected),
|
|
282
|
+
(400, "stash.watch.invalid_webhook_url", StashWatchInvalidWebhookUrl),
|
|
283
|
+
(502, "stash.watch.upstream_rejected", StashWatchUpstreamRejected),
|
|
284
|
+
(404, "stash.watch.not_found", StashWatchNotFound),
|
|
285
|
+
]
|
|
286
|
+
|
|
287
|
+
for status_code, code, error_class in cases:
|
|
288
|
+
with pytest.raises(error_class) as exc_info:
|
|
289
|
+
raise_for_status(
|
|
290
|
+
status_code,
|
|
291
|
+
"stash facade failed",
|
|
292
|
+
{"code": code, "category": "validation"},
|
|
293
|
+
"/svc/stash/example",
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
assert exc_info.value.code == code
|
|
297
|
+
assert exc_info.value.endpoint == "/svc/stash/example"
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
@pytest.mark.asyncio
|
|
301
|
+
async def test_bookmark_artifact_not_found_raises_typed_exception(monkeypatch, sdk):
|
|
302
|
+
from dominus import StashBookmarkArtifactNotFound
|
|
303
|
+
from dominus.errors import raise_for_status
|
|
304
|
+
|
|
305
|
+
async def fake_request(**kwargs):
|
|
306
|
+
raise_for_status(
|
|
307
|
+
404,
|
|
308
|
+
"Artifact not found for bookmark operation",
|
|
309
|
+
{"code": "stash.bookmark.artifact_not_found", "category": "not_found"},
|
|
310
|
+
kwargs["endpoint"],
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
314
|
+
|
|
315
|
+
with pytest.raises(StashBookmarkArtifactNotFound) as exc_info:
|
|
316
|
+
await sdk.stash.bookmark(
|
|
317
|
+
env="production",
|
|
318
|
+
kind="artifact",
|
|
319
|
+
scope="self",
|
|
320
|
+
key="my-key",
|
|
321
|
+
name="latest",
|
|
322
|
+
version_ref="v3",
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
assert exc_info.value.code == "stash.bookmark.artifact_not_found"
|
|
326
|
+
assert exc_info.value.endpoint == "/svc/stash/bookmark"
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
@pytest.mark.asyncio
|
|
330
|
+
async def test_watch_invalid_webhook_url_raises_typed_exception(monkeypatch, sdk):
|
|
331
|
+
from dominus import StashWatchInvalidWebhookUrl
|
|
332
|
+
from dominus.errors import raise_for_status
|
|
333
|
+
|
|
334
|
+
async def fake_request(**kwargs):
|
|
335
|
+
raise_for_status(
|
|
336
|
+
400,
|
|
337
|
+
"webhook_url must be an absolute http(s) URL",
|
|
338
|
+
{"code": "stash.watch.invalid_webhook_url", "category": "validation"},
|
|
339
|
+
kwargs["endpoint"],
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
monkeypatch.setattr(sdk, "_request", fake_request)
|
|
343
|
+
|
|
344
|
+
with pytest.raises(StashWatchInvalidWebhookUrl) as exc_info:
|
|
345
|
+
await sdk.stash.watch(
|
|
346
|
+
env="production",
|
|
347
|
+
kind="artifact",
|
|
348
|
+
scope="self",
|
|
349
|
+
key="my-key",
|
|
350
|
+
watcher_name="notify-reader",
|
|
351
|
+
webhook_url="not-a-url",
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
assert exc_info.value.code == "stash.watch.invalid_webhook_url"
|
|
355
|
+
assert exc_info.value.endpoint == "/svc/stash/watch"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus_sdk_python.egg-info/requires.txt
RENAMED
|
File without changes
|
{dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/dominus_sdk_python.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_authority_public_vocabulary.py
RENAMED
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_control_plane_namespaces.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dominus_sdk_python-6.2.0 → dominus_sdk_python-6.3.0}/tests/test_platform_coder_namespaces.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|