polyapi-python 0.3.1.dev0__py3-none-any.whl → 0.3.1.dev2__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.
- polyapi/__init__.py +4 -4
- polyapi/cli.py +165 -51
- polyapi/deployables.py +296 -0
- polyapi/function_cli.py +21 -212
- polyapi/generate.py +1 -2
- polyapi/parser.py +519 -0
- polyapi/prepare.py +135 -0
- polyapi/sync.py +122 -0
- polyapi/typedefs.py +21 -3
- {polyapi_python-0.3.1.dev0.dist-info → polyapi_python-0.3.1.dev2.dist-info}/METADATA +1 -1
- {polyapi_python-0.3.1.dev0.dist-info → polyapi_python-0.3.1.dev2.dist-info}/RECORD +14 -10
- {polyapi_python-0.3.1.dev0.dist-info → polyapi_python-0.3.1.dev2.dist-info}/WHEEL +1 -1
- {polyapi_python-0.3.1.dev0.dist-info → polyapi_python-0.3.1.dev2.dist-info}/LICENSE +0 -0
- {polyapi_python-0.3.1.dev0.dist-info → polyapi_python-0.3.1.dev2.dist-info}/top_level.txt +0 -0
polyapi/sync.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from typing import List, Dict
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
from polyapi.deployables import (
|
|
7
|
+
prepare_deployable_directory, load_deployable_records,
|
|
8
|
+
save_deployable_records, remove_deployable_records,
|
|
9
|
+
get_cache_deployments_revision, write_updated_deployable,
|
|
10
|
+
DeployableRecord, SyncDeployment, Deployment
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
DEPLOY_ORDER = [
|
|
14
|
+
'server-function',
|
|
15
|
+
'client-function',
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
def read_file(file_path: str) -> str:
|
|
19
|
+
with open(file_path, 'r', encoding='utf-8') as file:
|
|
20
|
+
return file.read()
|
|
21
|
+
|
|
22
|
+
def group_by(items: List[Dict], key: str) -> Dict[str, List[Dict]]:
|
|
23
|
+
grouped = {}
|
|
24
|
+
for item in items:
|
|
25
|
+
grouped.setdefault(item[key], []).append(item)
|
|
26
|
+
return grouped
|
|
27
|
+
|
|
28
|
+
def remove_deployable(deployable: SyncDeployment) -> bool:
|
|
29
|
+
# Example function call, adjust as needed
|
|
30
|
+
url = f"{deployable['instance']}/{deployable['type']}/{deployable['name']}"
|
|
31
|
+
response = requests.get(url)
|
|
32
|
+
if response.status_code != 200:
|
|
33
|
+
return False
|
|
34
|
+
requests.delete(url)
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
def sync_deployable_and_get_id(deployable: SyncDeployment, code: str) -> str:
|
|
38
|
+
# Example function call, adjust as needed
|
|
39
|
+
url = f"{deployable['instance']}/{deployable['type']}"
|
|
40
|
+
print(deployable)
|
|
41
|
+
payload = {
|
|
42
|
+
"context": deployable["context"],
|
|
43
|
+
"name": deployable["name"],
|
|
44
|
+
"description": deployable["description"],
|
|
45
|
+
"code": code,
|
|
46
|
+
"typeSchemas": deployable["typeSchemas"],
|
|
47
|
+
"config": deployable["config"]
|
|
48
|
+
}
|
|
49
|
+
response = requests.post(url, json=payload)
|
|
50
|
+
response.raise_for_status()
|
|
51
|
+
return response.json()['id']
|
|
52
|
+
|
|
53
|
+
def sync_deployable(deployable: SyncDeployment) -> Deployment:
|
|
54
|
+
code = read_file(deployable['file'])
|
|
55
|
+
id = sync_deployable_and_get_id(deployable, code)
|
|
56
|
+
return {
|
|
57
|
+
"name": deployable["name"],
|
|
58
|
+
"context": deployable["context"],
|
|
59
|
+
"instance": deployable["instance"],
|
|
60
|
+
"type": deployable["type"],
|
|
61
|
+
"id": id,
|
|
62
|
+
"deployed": datetime.now().isoformat(),
|
|
63
|
+
"fileRevision": deployable["fileRevision"],
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
def sync_deployables(dry_run: bool, instance: str = os.getenv('POLY_API_BASE_URL')):
|
|
67
|
+
prepare_deployable_directory()
|
|
68
|
+
git_revision = get_cache_deployments_revision()
|
|
69
|
+
all_deployables = load_deployable_records()
|
|
70
|
+
to_remove: List[DeployableRecord] = []
|
|
71
|
+
|
|
72
|
+
if not all_deployables:
|
|
73
|
+
print('No deployables found. Skipping sync.')
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
# TODO: Improve our deploy ordering.
|
|
77
|
+
# Right now we're doing rudimentary ordering by type
|
|
78
|
+
# But this does not safely handle cases where one server function may reference another
|
|
79
|
+
# We should parse the functions bodies for references to other Poly deployables and work them into a DAG
|
|
80
|
+
grouped_deployables = group_by(all_deployables, 'type')
|
|
81
|
+
for type_name in DEPLOY_ORDER:
|
|
82
|
+
deployables = grouped_deployables.get(type_name, [])
|
|
83
|
+
for deployable in deployables:
|
|
84
|
+
previous_deployment = next((d for d in deployable.get('deployments', []) if d['instance'] == instance), None)
|
|
85
|
+
git_revision_changed = git_revision != deployable['gitRevision']
|
|
86
|
+
file_revision_changed = not previous_deployment or previous_deployment['fileRevision'] != deployable['fileRevision']
|
|
87
|
+
|
|
88
|
+
action = 'REMOVED' if git_revision_changed else \
|
|
89
|
+
'ADDED' if not previous_deployment else \
|
|
90
|
+
'UPDATED' if file_revision_changed else 'OK'
|
|
91
|
+
|
|
92
|
+
if not dry_run and (git_revision_changed or file_revision_changed):
|
|
93
|
+
# Any deployable may be deployed to multiple instances/environments at the same time
|
|
94
|
+
# So we reduce the deployable record down to a single instance we want to deploy to
|
|
95
|
+
if previous_deployment:
|
|
96
|
+
sync_deployment = { **deployable, **previous_deployment, "instance": instance }
|
|
97
|
+
else:
|
|
98
|
+
sync_deployment = { **deployable, "instance": instance }
|
|
99
|
+
if git_revision == deployable['gitRevision']:
|
|
100
|
+
deployment = sync_deployable(sync_deployment)
|
|
101
|
+
print(deployment)
|
|
102
|
+
if previous_deployment:
|
|
103
|
+
previous_deployment.update(deployment)
|
|
104
|
+
else:
|
|
105
|
+
deployable['deployments'].insert(0, deployment)
|
|
106
|
+
else:
|
|
107
|
+
found = remove_deployable(sync_deployment)
|
|
108
|
+
action = 'NOT FOUND' if not found else action
|
|
109
|
+
remove_index = all_deployables.index(deployable)
|
|
110
|
+
to_remove.append(all_deployables.pop(remove_index))
|
|
111
|
+
|
|
112
|
+
print(f"{'Would sync' if dry_run else 'Synced'} {deployable['type'].replace('-', ' ')} {deployable['context']}.{deployable['name']}: {'TO BE ' if dry_run else ''}{action}")
|
|
113
|
+
|
|
114
|
+
if dry_run:
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
for deployable in all_deployables:
|
|
118
|
+
write_updated_deployable(deployable, True)
|
|
119
|
+
|
|
120
|
+
save_deployable_records(all_deployables)
|
|
121
|
+
if to_remove:
|
|
122
|
+
remove_deployable_records(to_remove)
|
polyapi/typedefs.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
from typing import Any, List, Literal, Dict,
|
|
2
|
-
from typing_extensions import NotRequired
|
|
1
|
+
from typing import Any, List, Literal, Dict, Union, Optional
|
|
2
|
+
from typing_extensions import NotRequired, TypedDict
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class PropertySpecification(TypedDict):
|
|
@@ -53,4 +53,22 @@ class VariableSpecDto(TypedDict):
|
|
|
53
53
|
name: str
|
|
54
54
|
description: str
|
|
55
55
|
variable: VariableSpecification
|
|
56
|
-
type: Literal['serverVariable']
|
|
56
|
+
type: Literal['serverVariable']
|
|
57
|
+
|
|
58
|
+
Visibility = Union[Literal['PUBLIC'], Literal['TENANT'], Literal['ENVIRONMENT']]
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class PolyDeployable(TypedDict, total=False):
|
|
62
|
+
context: str
|
|
63
|
+
name: str
|
|
64
|
+
disable_ai: Optional[bool] # Optional field to disable AI
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class PolyServerFunction(PolyDeployable):
|
|
68
|
+
logs_enabled: Optional[bool]
|
|
69
|
+
always_on: Optional[bool]
|
|
70
|
+
visibility: Optional[Visibility]
|
|
71
|
+
|
|
72
|
+
class PolyClientFunction(PolyDeployable):
|
|
73
|
+
logs_enabled: Optional[bool]
|
|
74
|
+
visibility: Optional[Visibility]
|
|
@@ -1,26 +1,30 @@
|
|
|
1
|
-
polyapi/__init__.py,sha256=
|
|
1
|
+
polyapi/__init__.py,sha256=a1Poy1kaTncYnUg6nWRcTjVm-R1CUQk12UX7VYQ9d5k,616
|
|
2
2
|
polyapi/__main__.py,sha256=V4zhAh_YGxno5f_KSrlkELxcuDh9bR3WSd0n-2r-qQQ,93
|
|
3
3
|
polyapi/api.py,sha256=e-8nOzq6SXD7_YPVBlW82_9wVxDCc8XD9ioMv_QvnH0,1877
|
|
4
4
|
polyapi/auth.py,sha256=zrIGatjba5GwUTNjKj1GHQWTEDP9B-HrSzCKbLFoqvc,5336
|
|
5
|
-
polyapi/cli.py,sha256=
|
|
5
|
+
polyapi/cli.py,sha256=wXR5UE73nk26WQRbE8yK69h3h5udNrZFr85ORhbPnRs,8251
|
|
6
6
|
polyapi/client.py,sha256=CoFDYvyKsqL4wPQbUDIr0Qb8Q5eD92xN4OEEcJEVuGQ,1296
|
|
7
7
|
polyapi/config.py,sha256=uvEvOfWYZTLmBmZX-5jJxCzWPpwzVmEOIiQIdi98P4Y,3015
|
|
8
8
|
polyapi/constants.py,sha256=sc-FnS0SngBLvSu1ZWMs0UCf9EYD1u1Yhfr-sZXGLns,607
|
|
9
|
+
polyapi/deployables.py,sha256=NihvDYrw7c-dB4Gfzwo7kiN2r4S74hs0azLuAPKXIR4,11849
|
|
9
10
|
polyapi/error_handler.py,sha256=I_e0iz6VM23FLVQWJljxs2NGcl_OODbi43OcbnqBlp8,2398
|
|
10
11
|
polyapi/exceptions.py,sha256=Zh7i7eCUhDuXEdUYjatkLFTeZkrx1BJ1P5ePgbJ9eIY,89
|
|
11
12
|
polyapi/execute.py,sha256=kXnvlNQ7nz9cRlV2_5gXH09UCmyiDP5zi3wiAw0uDuk,1943
|
|
12
|
-
polyapi/function_cli.py,sha256=
|
|
13
|
-
polyapi/generate.py,sha256=
|
|
13
|
+
polyapi/function_cli.py,sha256=TDoSuhj7lkx3LZfI4ndL0v1VJrKm-UNycoAO5EpZydA,4147
|
|
14
|
+
polyapi/generate.py,sha256=SIRfN7RF3Z7eQ8kSNg4H70LeT7Hmh-Mn5maibvM7kAM,7969
|
|
15
|
+
polyapi/parser.py,sha256=ySPA-pFllc-UuRc1vN3xuDqGSGZR1uo90Lk0VP_v5ak,20130
|
|
16
|
+
polyapi/prepare.py,sha256=s1FSAo4bSs7GXu6n49Hz3abxFrFGL5RZtx8TH6ftcYU,6378
|
|
14
17
|
polyapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
18
|
polyapi/rendered_spec.py,sha256=uaNzBhP4cX7iGfKwzZv0dxMagWzsGeDr0cQYx_AyIhQ,2153
|
|
16
19
|
polyapi/schema.py,sha256=VVMHAT5yU47cRC7xF44BrmUSemlk5oIKSxH2HTVPaQ8,3169
|
|
17
20
|
polyapi/server.py,sha256=NzQCZFSAJK7XiRw1kiU_i9uMvgYK7i8qh7UX2xjytJU,1908
|
|
18
|
-
polyapi/
|
|
21
|
+
polyapi/sync.py,sha256=JZ0Q8QCu8IgdwDIhO8PtDPagcmVanrtGqJIMdLDmai4,5051
|
|
22
|
+
polyapi/typedefs.py,sha256=jmKprGFQSxmJXvwV53p-MFMcStmTp-tsgsynWjoVmU0,1986
|
|
19
23
|
polyapi/utils.py,sha256=jzCh-ivKMcgp5fIXynhYmP9UyzsISr9bGGEzdPP8n3w,7644
|
|
20
24
|
polyapi/variables.py,sha256=d36-trnfTL_8m2NkorMiImb4O3UrJbiFV38CHxV5i0A,4200
|
|
21
25
|
polyapi/webhook.py,sha256=LWv28c2MLz_OKBI_Nn7WR4C-gs1SWgbdXsoxIIf-9UI,4886
|
|
22
|
-
polyapi_python-0.3.1.
|
|
23
|
-
polyapi_python-0.3.1.
|
|
24
|
-
polyapi_python-0.3.1.
|
|
25
|
-
polyapi_python-0.3.1.
|
|
26
|
-
polyapi_python-0.3.1.
|
|
26
|
+
polyapi_python-0.3.1.dev2.dist-info/LICENSE,sha256=Hi0kDr56Dsy0uYIwNt4r9G7tI8x8miXRTlyvbeplCP8,1068
|
|
27
|
+
polyapi_python-0.3.1.dev2.dist-info/METADATA,sha256=Q24DhrHmmS0oO4ZV3rfRqWnnyEq-nP_aWTedjzI4A94,5326
|
|
28
|
+
polyapi_python-0.3.1.dev2.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
|
|
29
|
+
polyapi_python-0.3.1.dev2.dist-info/top_level.txt,sha256=CEFllOnzowci_50RYJac-M54KD2IdAptFsayVVF_f04,8
|
|
30
|
+
polyapi_python-0.3.1.dev2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|