semaphoreui-client 0.1.0__py3-none-any.whl
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.
- semaphoreui_client/__about__.py +1 -0
- semaphoreui_client/__about__.py.backup +1 -0
- semaphoreui_client/__init__.py +1 -0
- semaphoreui_client/client.py +799 -0
- semaphoreui_client-0.1.0.dist-info/METADATA +20 -0
- semaphoreui_client-0.1.0.dist-info/RECORD +7 -0
- semaphoreui_client-0.1.0.dist-info/WHEEL +4 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.1.0"
|
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.1.0"
|
@@ -0,0 +1 @@
|
|
1
|
+
from .client import SemaphoreUIClient as Client # NOQA
|
@@ -0,0 +1,799 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
import typing
|
3
|
+
|
4
|
+
from dataclasses_json import dataclass_json
|
5
|
+
import requests
|
6
|
+
|
7
|
+
|
8
|
+
class SemaphoreUIClient:
|
9
|
+
|
10
|
+
def __init__(self, host, path="/api"):
|
11
|
+
self.http = requests.Session()
|
12
|
+
self.api_endpoint = f"{host}{path}"
|
13
|
+
|
14
|
+
def login(self, user, password):
|
15
|
+
response = self.http.post(
|
16
|
+
f"{self.api_endpoint}/auth/login", json={"auth": user, "password": password}
|
17
|
+
)
|
18
|
+
if response.status_code != 204:
|
19
|
+
raise ValueError(
|
20
|
+
f"Username and/or password incorrect. Response from POST /auth/login was {response.status_code}"
|
21
|
+
)
|
22
|
+
|
23
|
+
def whoami(self):
|
24
|
+
response = self.http.get(f"{self.api_endpoint}/auth/login")
|
25
|
+
assert (
|
26
|
+
response.status_code == 200
|
27
|
+
), f"GET /auth/login return response {response.status_code}"
|
28
|
+
|
29
|
+
def logout(self):
|
30
|
+
response = self.http.post(f"{self.api_endpoint}/auth/logout")
|
31
|
+
assert response.status_code == 204
|
32
|
+
|
33
|
+
def tokens(self) -> typing.List["Token"]:
|
34
|
+
response = self.http.get(f"{self.api_endpoint}/user/tokens")
|
35
|
+
assert response.status_code == 200
|
36
|
+
return [Token(**token_data, client=self) for token_data in response.json()]
|
37
|
+
|
38
|
+
def create_token(self) -> "Token":
|
39
|
+
response = self.http.post(f"{self.api_endpoint}/user/tokens")
|
40
|
+
assert response.status_code == 201
|
41
|
+
return Token(**response.json(), client=self)
|
42
|
+
|
43
|
+
def delete_token(self, id):
|
44
|
+
response = self.http.post(f"{self.api_endpoint}/user/tokens/{id}")
|
45
|
+
assert response.status_code in (204, 404) # 404 if token was already expired
|
46
|
+
|
47
|
+
def projects(self) -> typing.List["Project"]:
|
48
|
+
response = self.http.get(f"{self.api_endpoint}/projects")
|
49
|
+
assert response.status_code == 200
|
50
|
+
return [Project(**data, client=self) for data in response.json()]
|
51
|
+
|
52
|
+
def get_project(self, id: int) -> "Project":
|
53
|
+
response = self.http.get(f"{self.api_endpoint}/project/{id}")
|
54
|
+
assert response.status_code == 200
|
55
|
+
return Project(**response.json(), client=self)
|
56
|
+
|
57
|
+
def create_project(
|
58
|
+
self,
|
59
|
+
name: str,
|
60
|
+
alert: bool,
|
61
|
+
alert_chat: str,
|
62
|
+
max_parallel_tasks: int,
|
63
|
+
type: typing.Optional[str] = None,
|
64
|
+
demo: typing.Optional[bool] = False,
|
65
|
+
) -> "Project":
|
66
|
+
response = self.http.post(
|
67
|
+
f"{self.api_endpoint}/projects",
|
68
|
+
json={
|
69
|
+
"name": name,
|
70
|
+
"alert": alert,
|
71
|
+
"alert_chat": alert_chat,
|
72
|
+
"max_parallel_tasks": max_parallel_tasks,
|
73
|
+
"type": type,
|
74
|
+
"demo": demo,
|
75
|
+
},
|
76
|
+
)
|
77
|
+
assert response.status_code == 201
|
78
|
+
return Project(**response.json(), client=self)
|
79
|
+
|
80
|
+
def delete_project(self, id: int):
|
81
|
+
response = self.http.delete(f"{self.api_endpoint}/project/{id}")
|
82
|
+
assert response.status_code == 204
|
83
|
+
|
84
|
+
def update_project(
|
85
|
+
self,
|
86
|
+
id: int,
|
87
|
+
name: str,
|
88
|
+
alert: bool,
|
89
|
+
alert_chat: str,
|
90
|
+
max_parallel_tasks: int,
|
91
|
+
type: str,
|
92
|
+
):
|
93
|
+
response = self.http.put(
|
94
|
+
f"{self.api_endpoint}/project/{id}",
|
95
|
+
json={
|
96
|
+
"name": name,
|
97
|
+
"alert": alert,
|
98
|
+
},
|
99
|
+
)
|
100
|
+
assert response.status_code == 204
|
101
|
+
|
102
|
+
def backup_project(self, id: int) -> "ProjectBackup":
|
103
|
+
response = self.http.get(f"{self.api_endpoint}/project/{id}/backup")
|
104
|
+
assert response.status_code == 200
|
105
|
+
return ProjectBackup(**response.json())
|
106
|
+
|
107
|
+
def get_project_role(self, id: int) -> "Permissions":
|
108
|
+
response = self.http.get(f"{self.api_endpoint}/project/{id}/role")
|
109
|
+
assert response.status_code == 200
|
110
|
+
return Permissions(**response.json())
|
111
|
+
|
112
|
+
def get_project_events(self, id: int) -> typing.List["Event"]:
|
113
|
+
response = self.http.get(f"{self.api_endpoint}/project/{id}/events")
|
114
|
+
assert response.status_code == 200
|
115
|
+
return [Event(**data) for data in response.json()]
|
116
|
+
|
117
|
+
def get_project_users(self, id: int, sort: str, order: str) -> typing.List["User"]:
|
118
|
+
response = self.http.get(f"{self.api_endpoint}/project/{id}/")
|
119
|
+
assert response.status_code == 200
|
120
|
+
return [User(**data) for data in response.json()]
|
121
|
+
|
122
|
+
def add_project_user(self, id: int, user: "User"):
|
123
|
+
response = self.http.post(
|
124
|
+
f"{self.api_endpoint}/project/{id}/users", json=user.to_json() # type: ignore
|
125
|
+
)
|
126
|
+
assert response.status_code == 204
|
127
|
+
|
128
|
+
def update_project_user(self, id: int, user: "User"):
|
129
|
+
response = self.http.put(
|
130
|
+
f"{self.api_endpoint}/project/{id}/users/{user.id}", json=user.to_json() # type: ignore
|
131
|
+
)
|
132
|
+
assert response.status_code == 204
|
133
|
+
|
134
|
+
def remove_project_user(self, id: int, user_id: int):
|
135
|
+
response = self.http.delete(f"{self.api_endpoint}/project/{id}/users/{user_id}")
|
136
|
+
assert response.status_code == 204
|
137
|
+
|
138
|
+
def get_project_integrations(self, id: int) -> typing.List["Integration"]:
|
139
|
+
response = self.http.get(f"{self.api_endpoint}/project/{id}/integrations")
|
140
|
+
assert response.status_code == 200
|
141
|
+
return [Integration(**data, client=self) for data in response.json()]
|
142
|
+
|
143
|
+
def create_project_integrations(
|
144
|
+
self, project_id: int, name: str, template_id: int
|
145
|
+
) -> "Integration":
|
146
|
+
response = self.http.post(
|
147
|
+
f"{self.api_endpoint}/project/{id}integrations",
|
148
|
+
json={"project_id": project_id, "name": name, "template_id": template_id},
|
149
|
+
)
|
150
|
+
assert response.status_code == 200
|
151
|
+
return Integration(**response.json(), client=self)
|
152
|
+
|
153
|
+
def update_project_integration(
|
154
|
+
self, project_id: int, id: int, name: str, template_id: int
|
155
|
+
):
|
156
|
+
response = self.http.put(
|
157
|
+
f"{self.api_endpoint}/project/{project_id}/integrations/{id}",
|
158
|
+
json={"project_id": project_id, "name": name, "template_id": template_id},
|
159
|
+
)
|
160
|
+
assert response.status_code == 204
|
161
|
+
|
162
|
+
def delete_project_integration(self, project_id: int, id: int):
|
163
|
+
response = self.http.delete(
|
164
|
+
f"{self.api_endpoint}/project/{project_id}/integrations/{id}"
|
165
|
+
)
|
166
|
+
assert response.status_code == 204
|
167
|
+
|
168
|
+
def get_project_keys(
|
169
|
+
self,
|
170
|
+
project_id: int,
|
171
|
+
key_type: typing.Optional[str] = None,
|
172
|
+
sort: typing.Optional[str] = None,
|
173
|
+
order: typing.Optional[str] = None,
|
174
|
+
) -> typing.List["Key"]:
|
175
|
+
response = self.http.get(f"{self.api_endpoint}/project/{project_id}/keys")
|
176
|
+
assert response.status_code == 200
|
177
|
+
return [Key(**data, client=self) for data in response.json()]
|
178
|
+
|
179
|
+
def create_project_key(
|
180
|
+
self,
|
181
|
+
project_id: int,
|
182
|
+
name: str,
|
183
|
+
key_type: str,
|
184
|
+
override_secret: bool,
|
185
|
+
login_password: typing.Optional[typing.Tuple[str, str]],
|
186
|
+
ssh: typing.Optional[typing.Tuple[str, str, str]],
|
187
|
+
) -> "Key":
|
188
|
+
if key_type not in ("ssh", "login_password"):
|
189
|
+
raise ValueError(f"Invalid key_type: {key_type}. Acceptable values are: ssh, login_password")
|
190
|
+
if key_type == "ssh" and ssh is None:
|
191
|
+
raise ValueError("ssh parameter must be set on key_type: ssh")
|
192
|
+
elif key_type == "login_password" and login_password is None:
|
193
|
+
raise ValueError("login_password parameter must be set on key_type: login_password")
|
194
|
+
response = self.http.post(
|
195
|
+
f"{self.api_endpoint}/project/{project_id}/keys",
|
196
|
+
json={
|
197
|
+
"id": 0,
|
198
|
+
"project_id": project_id,
|
199
|
+
"name": name,
|
200
|
+
"type": key_type,
|
201
|
+
"override_secret": override_secret,
|
202
|
+
"login_password": {
|
203
|
+
"login": login_password[0],
|
204
|
+
"password": login_password[1],
|
205
|
+
},
|
206
|
+
"ssh": {
|
207
|
+
"login": ssh[0],
|
208
|
+
"passphrase": ssh[1],
|
209
|
+
"private_key": ssh[2],
|
210
|
+
},
|
211
|
+
},
|
212
|
+
)
|
213
|
+
assert response.status_code == 204
|
214
|
+
|
215
|
+
try:
|
216
|
+
return Key(**response.json(), client=self)
|
217
|
+
except ValueError:
|
218
|
+
# Sporadically, the response is an empty string. Get the actual key from the API
|
219
|
+
return [
|
220
|
+
key for key in self.get_project_keys(project_id) if key.name == name
|
221
|
+
][0]
|
222
|
+
|
223
|
+
def delete_project_key(self, project_id: int, id: int):
|
224
|
+
response = self.http.delete(
|
225
|
+
f"{self.api_endpoint}/project/{project_id}/keys/{id}"
|
226
|
+
)
|
227
|
+
assert response.status_code == 204
|
228
|
+
|
229
|
+
def get_project_repositories(self, project_id: int) -> typing.List["Repository"]:
|
230
|
+
response = self.http.get(
|
231
|
+
f"{self.api_endpoint}/project/{project_id}/repositories"
|
232
|
+
)
|
233
|
+
assert response.status_code == 200
|
234
|
+
return [Repository(**data, client=self) for data in response.json()]
|
235
|
+
|
236
|
+
def create_project_repository(
|
237
|
+
self, project_id: int, name: str, git_url: str, git_branch: str, ssh_key_id: int
|
238
|
+
) -> "Repository":
|
239
|
+
response = self.http.post(
|
240
|
+
f"{self.api_endpoint}/project/{project_id}/repositories",
|
241
|
+
json={
|
242
|
+
"name": name,
|
243
|
+
"project_id": project_id,
|
244
|
+
"git_url": git_url,
|
245
|
+
"git_branch": git_branch,
|
246
|
+
"ssh_key_id": ssh_key_id,
|
247
|
+
},
|
248
|
+
)
|
249
|
+
assert response.status_code == 204
|
250
|
+
try:
|
251
|
+
return Repository(**response.json(), client=self)
|
252
|
+
except ValueError:
|
253
|
+
return [
|
254
|
+
repo
|
255
|
+
for repo in self.get_project_repositories(project_id)
|
256
|
+
if repo.name == name
|
257
|
+
][0]
|
258
|
+
|
259
|
+
def delete_project_repository(self, project_id: int, id: int):
|
260
|
+
response = self.http.delete(
|
261
|
+
f"{self.api_endpoint}/project/{project_id}/repositories/{id}"
|
262
|
+
)
|
263
|
+
assert response.status_code == 204
|
264
|
+
|
265
|
+
def get_project_environments(self, project_id: int) -> typing.List["Environment"]:
|
266
|
+
response = self.http.get(
|
267
|
+
f"{self.api_endpoint}/project/{project_id}/environment"
|
268
|
+
)
|
269
|
+
assert response.status_code == 200
|
270
|
+
return [Environment(**data, client=self) for data in response.json()]
|
271
|
+
|
272
|
+
def create_project_environment(
|
273
|
+
self,
|
274
|
+
project_id: int,
|
275
|
+
name: str,
|
276
|
+
password: str,
|
277
|
+
json: str,
|
278
|
+
env: str,
|
279
|
+
secrets: typing.List[typing.Dict[typing.Any, typing.Any]],
|
280
|
+
) -> "Environment":
|
281
|
+
response = self.http.post(
|
282
|
+
f"{self.api_endpoint}/project/{project_id}/environment",
|
283
|
+
json={
|
284
|
+
"name": name,
|
285
|
+
"project_id": project_id,
|
286
|
+
"password": None,
|
287
|
+
"json": json,
|
288
|
+
"env": env,
|
289
|
+
"secrets": secrets,
|
290
|
+
},
|
291
|
+
)
|
292
|
+
assert response.status_code == 204
|
293
|
+
try:
|
294
|
+
return Environment(**response.json(), client=self)
|
295
|
+
except ValueError:
|
296
|
+
return [
|
297
|
+
env
|
298
|
+
for env in self.get_project_environments(project_id)
|
299
|
+
if env.name == name
|
300
|
+
][0]
|
301
|
+
|
302
|
+
def delete_project_environment(self, project_id: int, id: int):
|
303
|
+
response = self.http.delete(
|
304
|
+
f"{self.api_endpoint}/project/{project_id}/environment/{id}"
|
305
|
+
)
|
306
|
+
assert response.status_code == 204
|
307
|
+
|
308
|
+
def get_project_views(self, project_id: int) -> typing.List["View"]:
|
309
|
+
response = self.http.get(f"{self.api_endpoint}/project/{project_id}/views")
|
310
|
+
assert response.status_code == 200
|
311
|
+
return [View(**data, client=self) for data in response.json()]
|
312
|
+
|
313
|
+
def create_project_view(self, project_id: int, title: str, position: int) -> "View":
|
314
|
+
response = self.http.post(
|
315
|
+
f"{self.api_endpoint}/project/{project_id}/views",
|
316
|
+
json={"position": position, "title": title, "project_id": project_id},
|
317
|
+
)
|
318
|
+
assert response.status_code == 201
|
319
|
+
return View(**response.json(), client=self)
|
320
|
+
|
321
|
+
def delete_project_view(self, project_id: int, id: int):
|
322
|
+
response = self.http.delete(
|
323
|
+
f"{self.api_endpoint}/project/{project_id}/views/{id}"
|
324
|
+
)
|
325
|
+
assert response.status_code == 204
|
326
|
+
|
327
|
+
def get_project_inventories(self, project_id: int) -> typing.List["Inventory"]:
|
328
|
+
response = self.http.get(f"{self.api_endpoint}/project/{project_id}/inventory")
|
329
|
+
assert response.status_code == 200
|
330
|
+
return [Inventory(**data, client=self) for data in response.json()]
|
331
|
+
|
332
|
+
def create_project_inventory(
|
333
|
+
self,
|
334
|
+
project_id: int,
|
335
|
+
name: str,
|
336
|
+
inventory: str,
|
337
|
+
ssh_key_id: int,
|
338
|
+
become_key_id: int,
|
339
|
+
type: str,
|
340
|
+
repostory_id: int,
|
341
|
+
) -> "Inventory":
|
342
|
+
response = self.http.post(
|
343
|
+
f"{self.api_endpoint}/project/{project_id}/inventory",
|
344
|
+
json={
|
345
|
+
"id": 0,
|
346
|
+
"name": name,
|
347
|
+
"project_id": project_id,
|
348
|
+
"inventory": inventory,
|
349
|
+
"ssh_key_id": ssh_key_id,
|
350
|
+
"become_key_id": become_key_id,
|
351
|
+
"type": type,
|
352
|
+
"repository_id": repostory_id,
|
353
|
+
},
|
354
|
+
)
|
355
|
+
assert response.status_code == 201
|
356
|
+
return Inventory(**response.json(), client=self)
|
357
|
+
|
358
|
+
def delete_project_inventory(self, project_id: int, id: int):
|
359
|
+
response = self.http.delete(
|
360
|
+
f"{self.api_endpoint}/project/{project_id}/inventory/{id}"
|
361
|
+
)
|
362
|
+
assert response.status_code == 204
|
363
|
+
|
364
|
+
def get_project_templates(self, project_id: int) -> typing.List["Template"]:
|
365
|
+
response = self.http.get(f"{self.api_endpoint}/project/{project_id}/templates")
|
366
|
+
assert response.status_code == 200
|
367
|
+
return [Template(**data, client=self) for data in response.json()]
|
368
|
+
|
369
|
+
def create_project_template(
|
370
|
+
self,
|
371
|
+
project_id: int,
|
372
|
+
name: str,
|
373
|
+
repository_id: int,
|
374
|
+
inventory_id: int,
|
375
|
+
environment_id: int,
|
376
|
+
view_id: int,
|
377
|
+
vaults: typing.List[typing.Dict[str, typing.Any]],
|
378
|
+
playbook: str,
|
379
|
+
arguments: str,
|
380
|
+
description: str,
|
381
|
+
allow_override_args_in_task: bool,
|
382
|
+
limit: int,
|
383
|
+
suppress_success_alerts: bool,
|
384
|
+
app: str,
|
385
|
+
git_branch: str,
|
386
|
+
survey_vars: typing.List[typing.Dict[str, typing.Any]],
|
387
|
+
type: str,
|
388
|
+
start_version: str,
|
389
|
+
autorun: bool,
|
390
|
+
build_template_id: typing.Optional[int]=None,
|
391
|
+
) -> "Template":
|
392
|
+
response = self.http.post(
|
393
|
+
f"{self.api_endpoint}/project/{project_id}/templates",
|
394
|
+
json={
|
395
|
+
"id": 1,
|
396
|
+
"project_id": project_id,
|
397
|
+
"inventory_id": inventory_id,
|
398
|
+
"repository_id": repository_id,
|
399
|
+
"environment_id": environment_id,
|
400
|
+
"view_id": view_id,
|
401
|
+
"vaults": vaults,
|
402
|
+
"name": name,
|
403
|
+
"playbook": playbook,
|
404
|
+
"arguments": arguments,
|
405
|
+
"description": description,
|
406
|
+
"allow_override_args_in_task": allow_override_args_in_task,
|
407
|
+
"limit": limit,
|
408
|
+
"suppress_success_alerts": suppress_success_alerts,
|
409
|
+
"app": app,
|
410
|
+
"git_branch": git_branch,
|
411
|
+
"survey_vars": survey_vars,
|
412
|
+
"type": type,
|
413
|
+
"start_version": start_version,
|
414
|
+
"build_template_id": build_template_id,
|
415
|
+
"autorun": autorun,
|
416
|
+
},
|
417
|
+
)
|
418
|
+
assert (
|
419
|
+
response.status_code == 201
|
420
|
+
), f"Expected response code 201, got {response.status_code}"
|
421
|
+
return Template(**response.json(), client=self)
|
422
|
+
|
423
|
+
def delete_project_template(self, project_id: int, id: int):
|
424
|
+
response = self.http.delete(
|
425
|
+
f"{self.api_endpoint}/project/{project_id}/templates/{id}"
|
426
|
+
)
|
427
|
+
assert response.status_code == 204
|
428
|
+
|
429
|
+
|
430
|
+
@dataclass
|
431
|
+
class Integration:
|
432
|
+
"""A project integration"""
|
433
|
+
|
434
|
+
id: int
|
435
|
+
name: str
|
436
|
+
project_id: int
|
437
|
+
template_id: int
|
438
|
+
|
439
|
+
client: SemaphoreUIClient
|
440
|
+
|
441
|
+
def save(self):
|
442
|
+
self.client.update_project_integration(
|
443
|
+
self.project_id, self.id, self.name, self.template_id
|
444
|
+
)
|
445
|
+
|
446
|
+
def delete(self):
|
447
|
+
self.client.delete_project_integration(self.project_id, self.id)
|
448
|
+
|
449
|
+
|
450
|
+
@dataclass
|
451
|
+
class Token:
|
452
|
+
"""An authorization token."""
|
453
|
+
|
454
|
+
id: str
|
455
|
+
created: str
|
456
|
+
expired: bool
|
457
|
+
user_id: int
|
458
|
+
|
459
|
+
client: SemaphoreUIClient
|
460
|
+
|
461
|
+
def delete(self):
|
462
|
+
self.client.delete_token(self.id)
|
463
|
+
|
464
|
+
|
465
|
+
@dataclass
|
466
|
+
class Project:
|
467
|
+
"""A Semaphore UI project."""
|
468
|
+
|
469
|
+
id: int
|
470
|
+
name: str
|
471
|
+
created: str
|
472
|
+
alert: bool
|
473
|
+
alert_chat: str
|
474
|
+
max_parallel_tasks: int
|
475
|
+
type: str # This might be an enum?
|
476
|
+
|
477
|
+
client: SemaphoreUIClient
|
478
|
+
|
479
|
+
def delete(self):
|
480
|
+
self.client.delete_project(self.id)
|
481
|
+
|
482
|
+
def save(self):
|
483
|
+
self.client.update_project(
|
484
|
+
self.id,
|
485
|
+
self.name,
|
486
|
+
self.alert,
|
487
|
+
self.alert_chat,
|
488
|
+
self.max_parallel_tasks,
|
489
|
+
self.type,
|
490
|
+
)
|
491
|
+
|
492
|
+
def backup(self):
|
493
|
+
return self.client.backup_project(self.id)
|
494
|
+
|
495
|
+
def role(self):
|
496
|
+
return self.client.get_project_role(self.id)
|
497
|
+
|
498
|
+
def events(self):
|
499
|
+
return self.client.get_project_events(self.id)
|
500
|
+
|
501
|
+
def users(self, sort: str, order: str):
|
502
|
+
return self.client.get_project_users(self.id, sort, order)
|
503
|
+
|
504
|
+
def add_user(self, user: "User"):
|
505
|
+
return self.client.add_project_user(self.id, user)
|
506
|
+
|
507
|
+
def remove_user(self, user_id: int):
|
508
|
+
return self.client.remove_project_user(self.id, user_id)
|
509
|
+
|
510
|
+
def update_user(self, user: "User"):
|
511
|
+
return self.client.update_project_user(self.id, user)
|
512
|
+
|
513
|
+
def keys(self) -> typing.List["Key"]:
|
514
|
+
return self.client.get_project_keys(self.id)
|
515
|
+
|
516
|
+
def create_key(
|
517
|
+
self,
|
518
|
+
name: str,
|
519
|
+
key_type: str,
|
520
|
+
override_secret: bool,
|
521
|
+
string: str,
|
522
|
+
login_password: typing.Optional[typing.Tuple[str, str]],
|
523
|
+
ssh: typing.Optional[typing.Tuple[str, str, str]],
|
524
|
+
):
|
525
|
+
return self.client.create_project_key(
|
526
|
+
self.id, name, key_type, override_secret, login_password, ssh
|
527
|
+
)
|
528
|
+
|
529
|
+
def repositories(self) -> typing.List["Repository"]:
|
530
|
+
return self.client.get_project_repositories(self.id)
|
531
|
+
|
532
|
+
def create_repository(
|
533
|
+
self, name: str, git_url: str, git_branch: str, ssh_key_id: int
|
534
|
+
) -> "Repository":
|
535
|
+
return self.client.create_project_repository(
|
536
|
+
self.id, name, git_url, git_branch, ssh_key_id
|
537
|
+
)
|
538
|
+
|
539
|
+
def environments(self) -> typing.List["Environment"]:
|
540
|
+
return self.client.get_project_environments(self.id)
|
541
|
+
|
542
|
+
def create_environment(
|
543
|
+
self,
|
544
|
+
name: str,
|
545
|
+
password: str,
|
546
|
+
json: str,
|
547
|
+
env: str,
|
548
|
+
secrets: typing.List[typing.Dict[typing.Any, typing.Any]],
|
549
|
+
) -> "Environment":
|
550
|
+
return self.client.create_project_environment(
|
551
|
+
self.id, name, password, json, env, secrets
|
552
|
+
)
|
553
|
+
|
554
|
+
def views(self) -> typing.List["View"]:
|
555
|
+
return self.client.get_project_views(self.id)
|
556
|
+
|
557
|
+
def create_view(self, title: str, position: int) -> "View":
|
558
|
+
return self.client.create_project_view(self.id, title, position)
|
559
|
+
|
560
|
+
def inventories(self) -> typing.List["Inventory"]:
|
561
|
+
return self.client.get_project_inventories(self.id)
|
562
|
+
|
563
|
+
def create_inventory(
|
564
|
+
self,
|
565
|
+
name: str,
|
566
|
+
inventory: str,
|
567
|
+
ssh_key_id: int,
|
568
|
+
become_key_id: int,
|
569
|
+
type: str,
|
570
|
+
repository_id: int,
|
571
|
+
) -> "Inventory":
|
572
|
+
return self.client.create_project_inventory(
|
573
|
+
self.id, name, inventory, ssh_key_id, become_key_id, type, repository_id
|
574
|
+
)
|
575
|
+
|
576
|
+
def templates(self) -> typing.List["Template"]:
|
577
|
+
return self.client.get_project_templates(self.id)
|
578
|
+
|
579
|
+
def create_template(
|
580
|
+
self,
|
581
|
+
name: str,
|
582
|
+
repository_id: int,
|
583
|
+
inventory_id: int,
|
584
|
+
environment_id: int,
|
585
|
+
view_id: int,
|
586
|
+
vaults: typing.List[typing.Dict[str, typing.Any]],
|
587
|
+
playbook: str,
|
588
|
+
arguments: str,
|
589
|
+
description: str,
|
590
|
+
allow_override_args_in_task: bool,
|
591
|
+
limit: int,
|
592
|
+
suppress_success_alerts: bool,
|
593
|
+
app: str,
|
594
|
+
git_branch: str,
|
595
|
+
survey_vars: typing.List[typing.Dict[str, typing.Any]],
|
596
|
+
type: str,
|
597
|
+
start_version: str,
|
598
|
+
autorun: bool,
|
599
|
+
build_template_id: typing.Optional[int]=None,
|
600
|
+
) -> "Template":
|
601
|
+
return self.client.create_project_template(
|
602
|
+
self.id,
|
603
|
+
name,
|
604
|
+
repository_id,
|
605
|
+
inventory_id,
|
606
|
+
environment_id,
|
607
|
+
view_id,
|
608
|
+
vaults,
|
609
|
+
playbook,
|
610
|
+
arguments,
|
611
|
+
description,
|
612
|
+
allow_override_args_in_task,
|
613
|
+
limit,
|
614
|
+
suppress_success_alerts,
|
615
|
+
app,
|
616
|
+
git_branch,
|
617
|
+
survey_vars,
|
618
|
+
type,
|
619
|
+
start_version,
|
620
|
+
autorun,
|
621
|
+
build_template_id,
|
622
|
+
)
|
623
|
+
|
624
|
+
|
625
|
+
@dataclass
|
626
|
+
class Permissions:
|
627
|
+
role: str
|
628
|
+
permissions: int
|
629
|
+
|
630
|
+
|
631
|
+
@dataclass
|
632
|
+
class ProjectBackup: ...
|
633
|
+
|
634
|
+
|
635
|
+
@dataclass
|
636
|
+
class Event:
|
637
|
+
project_id: int
|
638
|
+
user_id: int
|
639
|
+
object_id: str
|
640
|
+
object_type: str
|
641
|
+
description: str
|
642
|
+
|
643
|
+
|
644
|
+
@dataclass_json
|
645
|
+
@dataclass
|
646
|
+
class User:
|
647
|
+
user_id: int
|
648
|
+
role: str
|
649
|
+
|
650
|
+
@property
|
651
|
+
def id(self) -> int:
|
652
|
+
return self.user_id
|
653
|
+
|
654
|
+
|
655
|
+
@dataclass
|
656
|
+
class KeySsh:
|
657
|
+
login: str
|
658
|
+
passphrase: str
|
659
|
+
private_key: str
|
660
|
+
|
661
|
+
|
662
|
+
@dataclass
|
663
|
+
class KeyLoginPassword:
|
664
|
+
login: str
|
665
|
+
password: str
|
666
|
+
|
667
|
+
|
668
|
+
@dataclass
|
669
|
+
class Key:
|
670
|
+
id: int
|
671
|
+
name: str
|
672
|
+
type: str
|
673
|
+
project_id: int
|
674
|
+
|
675
|
+
string: str
|
676
|
+
override_secret: bool
|
677
|
+
login_password: KeyLoginPassword
|
678
|
+
ssh: KeySsh
|
679
|
+
|
680
|
+
client: SemaphoreUIClient
|
681
|
+
|
682
|
+
@classmethod
|
683
|
+
def from_dict(cls, **keys) -> "Key":
|
684
|
+
ssh = KeySsh(
|
685
|
+
login=keys["ssh"]["login"],
|
686
|
+
passphrase=keys["ssh"]["passphrase"],
|
687
|
+
private_key=keys["ssh"]["private_key"],
|
688
|
+
)
|
689
|
+
login_password = KeyLoginPassword(
|
690
|
+
login=keys["login_password"]["login"],
|
691
|
+
password=keys["login_password"]["password"],
|
692
|
+
)
|
693
|
+
del keys["ssh"]
|
694
|
+
del keys["login_password"]
|
695
|
+
return cls(**keys, ssh=ssh, login_password=login_password)
|
696
|
+
|
697
|
+
def delete(self):
|
698
|
+
self.client.delete_project_key(self.project_id, self.id)
|
699
|
+
|
700
|
+
|
701
|
+
@dataclass
|
702
|
+
class Repository:
|
703
|
+
id: int
|
704
|
+
name: str
|
705
|
+
project_id: int
|
706
|
+
git_url: str
|
707
|
+
git_branch: str
|
708
|
+
ssh_key_id: int
|
709
|
+
|
710
|
+
client: SemaphoreUIClient
|
711
|
+
|
712
|
+
def delete(self):
|
713
|
+
self.client.delete_project_repository(self.project_id, self.id)
|
714
|
+
|
715
|
+
|
716
|
+
@dataclass
|
717
|
+
class Secret:
|
718
|
+
id: int
|
719
|
+
name: str
|
720
|
+
type: str
|
721
|
+
|
722
|
+
|
723
|
+
@dataclass
|
724
|
+
class Environment:
|
725
|
+
id: int
|
726
|
+
name: str
|
727
|
+
project_id: int
|
728
|
+
password: str
|
729
|
+
json: str
|
730
|
+
env: str
|
731
|
+
secrets: typing.List["Secret"]
|
732
|
+
|
733
|
+
client: SemaphoreUIClient
|
734
|
+
|
735
|
+
def delete(self):
|
736
|
+
self.client.delete_project_environment(self.project_id, self.id)
|
737
|
+
|
738
|
+
|
739
|
+
@dataclass
|
740
|
+
class View:
|
741
|
+
id: int
|
742
|
+
title: str
|
743
|
+
position: int
|
744
|
+
project_id: int
|
745
|
+
|
746
|
+
client: SemaphoreUIClient
|
747
|
+
|
748
|
+
def delete(self):
|
749
|
+
self.client.delete_project_view(self.project_id, self.id)
|
750
|
+
|
751
|
+
|
752
|
+
@dataclass
|
753
|
+
class Inventory:
|
754
|
+
id: int
|
755
|
+
name: str
|
756
|
+
project_id: int
|
757
|
+
inventory: str
|
758
|
+
ssh_key_id: int
|
759
|
+
become_key_id: int
|
760
|
+
type: str
|
761
|
+
|
762
|
+
holder_id: int
|
763
|
+
repository_id: int
|
764
|
+
|
765
|
+
client: SemaphoreUIClient
|
766
|
+
|
767
|
+
def delete(self):
|
768
|
+
self.client.delete_project_inventory(self.project_id, self.id)
|
769
|
+
|
770
|
+
|
771
|
+
@dataclass
|
772
|
+
class Template:
|
773
|
+
id: int
|
774
|
+
project_id: int
|
775
|
+
repository_id: int
|
776
|
+
inventory_id: int
|
777
|
+
environment_id: int
|
778
|
+
view_id: int
|
779
|
+
name: str
|
780
|
+
playbook: str
|
781
|
+
arguments: str
|
782
|
+
description: str
|
783
|
+
allow_override_args_in_task: bool
|
784
|
+
suppress_success_alerts: bool
|
785
|
+
app: str
|
786
|
+
survey_vars: typing.List[typing.Dict[str, typing.Any]]
|
787
|
+
type: str
|
788
|
+
start_version: str
|
789
|
+
build_template_id: int
|
790
|
+
autorun: bool
|
791
|
+
vault_key_id: int
|
792
|
+
last_task: int
|
793
|
+
tasks: int
|
794
|
+
|
795
|
+
|
796
|
+
client: SemaphoreUIClient
|
797
|
+
|
798
|
+
def delete(self):
|
799
|
+
self.client.delete_project_template(self.project_id, self.id)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: semaphoreui-client
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: An api client for interacting with Semaphore UI
|
5
|
+
Project-URL: Documentation, https://github.com/Paul Hummer/semaphoreui-client#readme
|
6
|
+
Project-URL: Issues, https://github.com/Paul Hummer/semaphoreui-client/issues
|
7
|
+
Project-URL: Source, https://github.com/Paul Hummer/semaphoreui-client
|
8
|
+
Author-email: Paul Hummer <paul@eventuallyanyway.com>
|
9
|
+
License-Expression: MIT
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
11
|
+
Classifier: Programming Language :: Python
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
16
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
18
|
+
Requires-Python: >=3.9
|
19
|
+
Requires-Dist: dataclasses-json>=0.6.7
|
20
|
+
Requires-Dist: requests>=2.32.3
|
@@ -0,0 +1,7 @@
|
|
1
|
+
semaphoreui_client/__about__.py,sha256=Pru0BlFBASFCFo7McHdohtKkUtgMPDwbGfyUZlE2_Vw,21
|
2
|
+
semaphoreui_client/__about__.py.backup,sha256=Pru0BlFBASFCFo7McHdohtKkUtgMPDwbGfyUZlE2_Vw,21
|
3
|
+
semaphoreui_client/__init__.py,sha256=r2j1tTgwFzp3AKAktr8izDIXllRf-Y0SdHAjInYDTP0,55
|
4
|
+
semaphoreui_client/client.py,sha256=dTR1ExrXwGOtPXTqmQZx5iia7uZ8zlDAkFZC_5t-3Bo,24280
|
5
|
+
semaphoreui_client-0.1.0.dist-info/METADATA,sha256=HgH0R8iNzgUhehXqm3xX3cLanj_ZHypl5J34IEq4TBE,955
|
6
|
+
semaphoreui_client-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
7
|
+
semaphoreui_client-0.1.0.dist-info/RECORD,,
|