validio-cli 0.20.2__tar.gz → 0.22.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.
- {validio_cli-0.20.2 → validio_cli-0.22.0}/PKG-INFO +1 -1
- {validio_cli-0.20.2 → validio_cli-0.22.0}/pyproject.toml +1 -1
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/code.py +67 -0
- validio_cli-0.22.0/validio_cli/bin/entities/namespaces.py +203 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/users.py +2 -6
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/main.py +2 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/LICENSE +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/README_PUBLIC.md +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/__init__.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/channels.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/config.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/credentials.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/dbt.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/incidents.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/metrics.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/notification_rules.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/recommendations.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/resources.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/segmentations.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/segments.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/sources.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/validators.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/bin/entities/windows.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/components.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/metadata.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/namespace.py +0 -0
- {validio_cli-0.20.2 → validio_cli-0.22.0}/validio_cli/schema.py +0 -0
|
@@ -3,7 +3,7 @@ name = "validio-cli"
|
|
|
3
3
|
# This version does not represent the released version or any tag. For each
|
|
4
4
|
# release we automatically bump this before building and publishing so this
|
|
5
5
|
# should be kept at 0.0.1dev1
|
|
6
|
-
version = "0.
|
|
6
|
+
version = "0.22.0"
|
|
7
7
|
description = "CLI tool to interact with the Validio platform"
|
|
8
8
|
authors = ["Validio <support@validio.io>"]
|
|
9
9
|
license = "Apache-2.0"
|
|
@@ -15,6 +15,10 @@ from validio_sdk.code import scaffold
|
|
|
15
15
|
from validio_sdk.resource._diff import DiffContext, GraphDiff, ResourceUpdate
|
|
16
16
|
from validio_sdk.resource._resource import Resource
|
|
17
17
|
from validio_sdk.resource._util import SourceSchemaReinference
|
|
18
|
+
from validio_sdk.resource.replacement import (
|
|
19
|
+
ImmutableFieldReplacementReason,
|
|
20
|
+
ReplacementReason,
|
|
21
|
+
)
|
|
18
22
|
from validio_sdk.validio_client import ValidioAPIClient
|
|
19
23
|
|
|
20
24
|
from validio_cli import AsyncTyper, ConfigDir, Namespace, get_client_and_config
|
|
@@ -368,6 +372,7 @@ def _show_resources_diff(
|
|
|
368
372
|
for t in resource_types:
|
|
369
373
|
_show_create_resource_diff(
|
|
370
374
|
getattr(diff.to_create, t),
|
|
375
|
+
getattr(diff.replacement_ctx, t),
|
|
371
376
|
show_schema,
|
|
372
377
|
show_secrets,
|
|
373
378
|
escape,
|
|
@@ -378,6 +383,7 @@ def _show_resources_diff(
|
|
|
378
383
|
for t in resource_types:
|
|
379
384
|
_show_delete_resource_diff(
|
|
380
385
|
getattr(diff.to_delete, t),
|
|
386
|
+
getattr(diff.replacement_ctx, t),
|
|
381
387
|
show_schema,
|
|
382
388
|
show_secrets,
|
|
383
389
|
escape,
|
|
@@ -394,6 +400,16 @@ def _show_resources_diff(
|
|
|
394
400
|
diff_output=diff_output,
|
|
395
401
|
)
|
|
396
402
|
|
|
403
|
+
for t in resource_types:
|
|
404
|
+
_show_replace_resource_diff(
|
|
405
|
+
getattr(diff.to_create, t),
|
|
406
|
+
getattr(diff.replacement_ctx, t),
|
|
407
|
+
show_schema,
|
|
408
|
+
show_secrets,
|
|
409
|
+
escape,
|
|
410
|
+
diff_output,
|
|
411
|
+
)
|
|
412
|
+
|
|
397
413
|
_show_deprecations(deprecations)
|
|
398
414
|
|
|
399
415
|
print(
|
|
@@ -405,12 +421,16 @@ def _show_resources_diff(
|
|
|
405
421
|
|
|
406
422
|
def _show_create_resource_diff(
|
|
407
423
|
resources: Mapping[str, Resource],
|
|
424
|
+
replaced_resources: Mapping[str, ReplacementReason],
|
|
408
425
|
show_schema: bool,
|
|
409
426
|
show_secrets: bool,
|
|
410
427
|
color: bool,
|
|
411
428
|
diff_output: DiffOutput,
|
|
412
429
|
) -> None:
|
|
413
430
|
for r in resources.values():
|
|
431
|
+
if r.name in replaced_resources:
|
|
432
|
+
continue
|
|
433
|
+
|
|
414
434
|
class_key = r.__class__.__name__
|
|
415
435
|
|
|
416
436
|
print(f"{class_key} '{r.name}' will be created")
|
|
@@ -425,12 +445,16 @@ def _show_create_resource_diff(
|
|
|
425
445
|
|
|
426
446
|
def _show_delete_resource_diff(
|
|
427
447
|
resources: Mapping[str, Resource],
|
|
448
|
+
replaced_resources: Mapping[str, ReplacementReason],
|
|
428
449
|
show_schema: bool,
|
|
429
450
|
show_secrets: bool,
|
|
430
451
|
color: bool,
|
|
431
452
|
diff_output: DiffOutput,
|
|
432
453
|
) -> None:
|
|
433
454
|
for r in resources.values():
|
|
455
|
+
if r.name in replaced_resources:
|
|
456
|
+
continue
|
|
457
|
+
|
|
434
458
|
class_key = r.__class__.__name__
|
|
435
459
|
|
|
436
460
|
print(f"{class_key} '{r.name}' will be deleted")
|
|
@@ -475,6 +499,49 @@ def _show_update_resource_diff(
|
|
|
475
499
|
_show_diff(b_value, a_value, color, diff_output, class_key)
|
|
476
500
|
|
|
477
501
|
|
|
502
|
+
def _show_replace_resource_diff(
|
|
503
|
+
resources: Mapping[str, Resource],
|
|
504
|
+
replaced_resources: Mapping[str, ReplacementReason],
|
|
505
|
+
show_schema: bool,
|
|
506
|
+
show_secrets: bool,
|
|
507
|
+
color: bool,
|
|
508
|
+
diff_output: DiffOutput,
|
|
509
|
+
) -> None:
|
|
510
|
+
for r in resources.values():
|
|
511
|
+
reason = replaced_resources.get(r.name)
|
|
512
|
+
if not reason:
|
|
513
|
+
continue
|
|
514
|
+
|
|
515
|
+
class_key = r.__class__.__name__
|
|
516
|
+
|
|
517
|
+
print(f"{class_key} '{r.name}' will be replaced: {reason._reason()}")
|
|
518
|
+
|
|
519
|
+
rewrites = _diff_field_rewrites(show_schema)
|
|
520
|
+
a_value, b_value = (None, None)
|
|
521
|
+
if isinstance(reason, ImmutableFieldReplacementReason):
|
|
522
|
+
update = reason.resource_update
|
|
523
|
+
a_value = code_plan._create_resource_diff_object(
|
|
524
|
+
update.manifest,
|
|
525
|
+
show_secrets=show_secrets,
|
|
526
|
+
rewrites=rewrites,
|
|
527
|
+
secrets_changed=update.secrets_changed,
|
|
528
|
+
is_manifest=True,
|
|
529
|
+
)
|
|
530
|
+
b_value = code_plan._create_resource_diff_object(
|
|
531
|
+
update.server,
|
|
532
|
+
show_secrets=show_secrets,
|
|
533
|
+
rewrites=rewrites,
|
|
534
|
+
secrets_changed=update.secrets_changed,
|
|
535
|
+
is_manifest=False,
|
|
536
|
+
)
|
|
537
|
+
else:
|
|
538
|
+
b_value = code_plan._create_resource_diff_object(
|
|
539
|
+
r, rewrites=rewrites, show_secrets=show_secrets
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
_show_diff(a_value, b_value, color, diff_output, class_key)
|
|
543
|
+
|
|
544
|
+
|
|
478
545
|
def _show_diff(
|
|
479
546
|
current_value: Any,
|
|
480
547
|
new_value: Any,
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
import typer
|
|
4
|
+
from validio_sdk import ValidioError
|
|
5
|
+
from validio_sdk.graphql_client.enums import Role
|
|
6
|
+
from validio_sdk.graphql_client.input_types import (
|
|
7
|
+
NamespaceCreateInput,
|
|
8
|
+
NamespaceRolesUpdateInput,
|
|
9
|
+
NamespaceRoleWithId,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
from validio_cli import (
|
|
13
|
+
AsyncTyper,
|
|
14
|
+
ConfigDir,
|
|
15
|
+
OutputFormat,
|
|
16
|
+
OutputFormatOption,
|
|
17
|
+
OutputSettings,
|
|
18
|
+
_single_resource_if_specified,
|
|
19
|
+
get_client_and_config,
|
|
20
|
+
output_json,
|
|
21
|
+
output_text,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
app = AsyncTyper(help="Namespaces used to separate resources")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@app.async_command(help="Get namespaces")
|
|
28
|
+
async def get(
|
|
29
|
+
config_dir: str = ConfigDir,
|
|
30
|
+
output_format: OutputFormat = OutputFormatOption,
|
|
31
|
+
identifier: str = typer.Argument(default=None, help="Namespace name"),
|
|
32
|
+
) -> None:
|
|
33
|
+
vc, _ = await get_client_and_config(config_dir)
|
|
34
|
+
|
|
35
|
+
namespaces = await vc.list_namespaces()
|
|
36
|
+
# TODO(UI-2311): Fully support list/get/get_by_resource_name
|
|
37
|
+
namespaces = _single_resource_if_specified(namespaces, identifier)
|
|
38
|
+
|
|
39
|
+
if output_format == OutputFormat.JSON:
|
|
40
|
+
return output_json(namespaces, identifier)
|
|
41
|
+
|
|
42
|
+
return output_text(
|
|
43
|
+
namespaces,
|
|
44
|
+
fields={
|
|
45
|
+
"name": OutputSettings(attribute_name="id"),
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@app.async_command(help="[red][bold]BETA[/bold][/red] Create a namespace")
|
|
51
|
+
async def create(
|
|
52
|
+
config_dir: str = ConfigDir,
|
|
53
|
+
output_format: OutputFormat = OutputFormatOption,
|
|
54
|
+
identifier: str = typer.Argument(..., help="Namespace name"),
|
|
55
|
+
role: Role = typer.Option(None, help="The role to assign --api-key and --member"),
|
|
56
|
+
api_key: list[str] = typer.Option(
|
|
57
|
+
[],
|
|
58
|
+
"--api-key",
|
|
59
|
+
help="API key to assign the --role. Can be specified multiple times",
|
|
60
|
+
),
|
|
61
|
+
member: list[str] = typer.Option(
|
|
62
|
+
[],
|
|
63
|
+
"--member",
|
|
64
|
+
help="Member id to assign to the --role. Can be specified multiple times",
|
|
65
|
+
),
|
|
66
|
+
name: Optional[str] = None,
|
|
67
|
+
) -> None:
|
|
68
|
+
vc, cfg = await get_client_and_config(config_dir)
|
|
69
|
+
|
|
70
|
+
if (member or api_key) and not role:
|
|
71
|
+
raise ValidioError("--role is required when specifying --member or --api-key")
|
|
72
|
+
|
|
73
|
+
if role and not (member or api_key):
|
|
74
|
+
raise ValidioError(
|
|
75
|
+
"--role is specified but no --member or --api-key to assign the role"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
ns_api_keys = [
|
|
79
|
+
NamespaceRoleWithId(
|
|
80
|
+
id=cfg.access_key,
|
|
81
|
+
role=Role.ADMIN,
|
|
82
|
+
)
|
|
83
|
+
]
|
|
84
|
+
for ak in api_key:
|
|
85
|
+
ns_api_keys.append(NamespaceRoleWithId(id=ak, role=role))
|
|
86
|
+
|
|
87
|
+
ns_members = []
|
|
88
|
+
for m in member:
|
|
89
|
+
ns_members.append(NamespaceRoleWithId(id=m, role=role))
|
|
90
|
+
|
|
91
|
+
namespaces = await vc.create_namespace(
|
|
92
|
+
NamespaceCreateInput(
|
|
93
|
+
id=identifier,
|
|
94
|
+
name=name or identifier,
|
|
95
|
+
members=ns_members,
|
|
96
|
+
api_keys=ns_api_keys,
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
if output_format == OutputFormat.JSON:
|
|
101
|
+
return output_json(namespaces, identifier)
|
|
102
|
+
|
|
103
|
+
return output_text(
|
|
104
|
+
namespaces.namespace,
|
|
105
|
+
fields={
|
|
106
|
+
"id": None,
|
|
107
|
+
"name": None,
|
|
108
|
+
},
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@app.async_command(help="[red][bold]BETA[/bold][/red] Update a namespace")
|
|
113
|
+
async def update(
|
|
114
|
+
config_dir: str = ConfigDir,
|
|
115
|
+
output_format: OutputFormat = OutputFormatOption,
|
|
116
|
+
identifier: str = typer.Argument(..., help="Namespace name"),
|
|
117
|
+
role: Role = typer.Option(None, help="The role to assign --api-key and --member"),
|
|
118
|
+
api_key: list[str] = typer.Option(
|
|
119
|
+
[],
|
|
120
|
+
"--api-key",
|
|
121
|
+
help="API key to assign the --role. Can be specified multiple times",
|
|
122
|
+
),
|
|
123
|
+
member: list[str] = typer.Option(
|
|
124
|
+
[],
|
|
125
|
+
"--member",
|
|
126
|
+
help="Member id to assign to the --role. Can be specified multiple times",
|
|
127
|
+
),
|
|
128
|
+
) -> None:
|
|
129
|
+
vc, _ = await get_client_and_config(config_dir)
|
|
130
|
+
|
|
131
|
+
if (member or api_key) and not role:
|
|
132
|
+
raise ValidioError("--role is required when specifying --member or --api-key")
|
|
133
|
+
|
|
134
|
+
if role and not (member or api_key):
|
|
135
|
+
raise ValidioError(
|
|
136
|
+
"--role is specified but no --member or --api-key to assign the role"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
ns_api_keys = []
|
|
140
|
+
for ak in api_key:
|
|
141
|
+
ns_api_keys.append(NamespaceRoleWithId(id=ak, role=role))
|
|
142
|
+
|
|
143
|
+
ns_members = []
|
|
144
|
+
for m in member:
|
|
145
|
+
ns_members.append(NamespaceRoleWithId(id=m, role=role))
|
|
146
|
+
|
|
147
|
+
namespace = await vc.get_namespace(identifier)
|
|
148
|
+
if namespace is None:
|
|
149
|
+
raise ValidioError(f"namespace '{identifier}' not found")
|
|
150
|
+
|
|
151
|
+
api_keys = [
|
|
152
|
+
NamespaceRoleWithId(id=x.api_key.id, role=x.role)
|
|
153
|
+
for x in namespace.api_keys
|
|
154
|
+
if x.api_key.id not in api_key
|
|
155
|
+
] + ns_api_keys
|
|
156
|
+
|
|
157
|
+
members = [
|
|
158
|
+
NamespaceRoleWithId(id=x.user.id, role=x.role)
|
|
159
|
+
for x in namespace.members
|
|
160
|
+
if x.user.id not in member
|
|
161
|
+
] + ns_members
|
|
162
|
+
|
|
163
|
+
namespaces = await vc.update_namespace_roles(
|
|
164
|
+
NamespaceRolesUpdateInput(
|
|
165
|
+
namespace_id=identifier,
|
|
166
|
+
members=members,
|
|
167
|
+
api_keys=api_keys,
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
if output_format == OutputFormat.JSON:
|
|
172
|
+
return output_json(namespaces, identifier)
|
|
173
|
+
|
|
174
|
+
return output_text(
|
|
175
|
+
namespaces.namespace,
|
|
176
|
+
fields={
|
|
177
|
+
"id": None,
|
|
178
|
+
"name": None,
|
|
179
|
+
},
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@app.async_command(help="Remove a namespace")
|
|
184
|
+
async def remove(
|
|
185
|
+
config_dir: str = ConfigDir,
|
|
186
|
+
output_format: OutputFormat = OutputFormatOption,
|
|
187
|
+
identifier: str = typer.Argument(..., help="Namespace name"),
|
|
188
|
+
) -> None:
|
|
189
|
+
vc, _ = await get_client_and_config(config_dir)
|
|
190
|
+
|
|
191
|
+
result = await vc.delete_namespaces(ids=[identifier])
|
|
192
|
+
|
|
193
|
+
if output_format == OutputFormat.JSON:
|
|
194
|
+
return output_json(result, identifier)
|
|
195
|
+
|
|
196
|
+
status = "OK" if len(result.errors) == 0 else "ERROR"
|
|
197
|
+
|
|
198
|
+
return output_text(
|
|
199
|
+
{"status": status},
|
|
200
|
+
fields={
|
|
201
|
+
"status": OutputSettings(pass_full_object=True, reformat=lambda _: status),
|
|
202
|
+
},
|
|
203
|
+
)
|
|
@@ -4,7 +4,6 @@ from validio_cli import (
|
|
|
4
4
|
AsyncTyper,
|
|
5
5
|
ConfigDir,
|
|
6
6
|
Identifier,
|
|
7
|
-
Namespace,
|
|
8
7
|
OutputFormat,
|
|
9
8
|
OutputFormatOption,
|
|
10
9
|
OutputSettings,
|
|
@@ -12,7 +11,6 @@ from validio_cli import (
|
|
|
12
11
|
output_json,
|
|
13
12
|
output_text,
|
|
14
13
|
)
|
|
15
|
-
from validio_cli.namespace import get_namespace
|
|
16
14
|
|
|
17
15
|
app = AsyncTyper(help="Users in the Validio platform")
|
|
18
16
|
|
|
@@ -21,7 +19,6 @@ app = AsyncTyper(help="Users in the Validio platform")
|
|
|
21
19
|
async def get(
|
|
22
20
|
config_dir: str = ConfigDir,
|
|
23
21
|
output_format: OutputFormat = OutputFormatOption,
|
|
24
|
-
namespace: str = Namespace(),
|
|
25
22
|
identifier: str = Identifier,
|
|
26
23
|
) -> None:
|
|
27
24
|
vc, cfg = await get_client_and_config(config_dir)
|
|
@@ -30,7 +27,6 @@ async def get(
|
|
|
30
27
|
users = [
|
|
31
28
|
await vc.get_user_by_resource_name(
|
|
32
29
|
resource_name=identifier,
|
|
33
|
-
namespace_id=get_namespace(namespace, cfg),
|
|
34
30
|
)
|
|
35
31
|
]
|
|
36
32
|
else:
|
|
@@ -43,8 +39,8 @@ async def get(
|
|
|
43
39
|
users,
|
|
44
40
|
fields={
|
|
45
41
|
"name": OutputSettings(attribute_name="resource_name"),
|
|
46
|
-
"
|
|
47
|
-
"status":
|
|
42
|
+
"global_role": OutputSettings(reformat=lambda x: x.value),
|
|
43
|
+
"status": OutputSettings(reformat=lambda x: x.value),
|
|
48
44
|
"identities": OutputSettings(reformat=lambda x: len(x)),
|
|
49
45
|
"age": OutputSettings(attribute_name="created_at"),
|
|
50
46
|
},
|
|
@@ -25,6 +25,7 @@ from validio_cli.bin.entities import (
|
|
|
25
25
|
dbt,
|
|
26
26
|
incidents,
|
|
27
27
|
metrics,
|
|
28
|
+
namespaces,
|
|
28
29
|
notification_rules,
|
|
29
30
|
recommendations,
|
|
30
31
|
resources,
|
|
@@ -50,6 +51,7 @@ app.add_typer(credentials.app, no_args_is_help=True, name="credentials")
|
|
|
50
51
|
app.add_typer(dbt.app, no_args_is_help=True, name="dbt")
|
|
51
52
|
app.add_typer(incidents.app, no_args_is_help=True, name="incidents")
|
|
52
53
|
app.add_typer(metrics.app, no_args_is_help=True, name="metrics")
|
|
54
|
+
app.add_typer(namespaces.app, no_args_is_help=True, name="namespaces")
|
|
53
55
|
app.add_typer(resources.app, no_args_is_help=True, name="resources")
|
|
54
56
|
app.add_typer(notification_rules.app, no_args_is_help=True, name="notification-rules")
|
|
55
57
|
app.add_typer(recommendations.app, no_args_is_help=True, name="recommendations")
|
|
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
|