validio-cli 8.2.1__tar.gz → 9.0.1__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-8.2.1 → validio_cli-9.0.1}/PKG-INFO +1 -1
- {validio_cli-8.2.1 → validio_cli-9.0.1}/pyproject.toml +1 -1
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/__init__.py +20 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/code.py +53 -2
- validio_cli-9.0.1/validio_cli/bin/entities/integrations.py +109 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/main.py +24 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/LICENSE +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/README_PUBLIC.md +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/channels.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/config.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/credentials.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/dbt.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/filters.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/incidents.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/metrics.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/namespaces.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/notification_rules.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/resources.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/segmentations.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/segments.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/sources.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/users.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/validators.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/bin/entities/windows.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/components.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/metadata.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/validio_cli/namespace.py +0 -0
- {validio_cli-8.2.1 → validio_cli-9.0.1}/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 = "
|
|
6
|
+
version = "9.0.1"
|
|
7
7
|
description = "CLI tool to interact with the Validio platform"
|
|
8
8
|
authors = ["Validio <support@validio.io>"]
|
|
9
9
|
license = "Apache-2.0"
|
|
@@ -17,6 +17,7 @@ from tabulate import tabulate
|
|
|
17
17
|
from validio_sdk import config
|
|
18
18
|
from validio_sdk._api.api import APIClient
|
|
19
19
|
from validio_sdk.config import Config, ValidioConfig
|
|
20
|
+
from validio_sdk.features import Feature, all_features, set_enabled
|
|
20
21
|
from validio_sdk.util import ClassJSONEncoder
|
|
21
22
|
|
|
22
23
|
F = TypeVar("F", bound=Callable[..., Any])
|
|
@@ -267,3 +268,22 @@ def _resource_filter(
|
|
|
267
268
|
def _fixed_width(message: str, width: int = 25) -> str:
|
|
268
269
|
message = f"{message}: "
|
|
269
270
|
return f"{message:<{width}} "
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def _apply_feature_flags(feature: list[Feature], all_features_flag: bool) -> None:
|
|
274
|
+
"""Apply feature-flag selection from CLI options.
|
|
275
|
+
|
|
276
|
+
Shared between the root callback and sub-app callbacks so users can pass
|
|
277
|
+
``--feature`` / ``--all-features`` at any position. The helper only mutates
|
|
278
|
+
the env var when the current callback actually received flag values — this
|
|
279
|
+
way a root-level selection isn't clobbered by a downstream callback that
|
|
280
|
+
was invoked without flags.
|
|
281
|
+
"""
|
|
282
|
+
if all_features_flag:
|
|
283
|
+
set_enabled(all_features())
|
|
284
|
+
return
|
|
285
|
+
|
|
286
|
+
if not feature:
|
|
287
|
+
return
|
|
288
|
+
|
|
289
|
+
set_enabled(frozenset(feature))
|
|
@@ -12,8 +12,14 @@ from validio_sdk.code import _import as code_import
|
|
|
12
12
|
from validio_sdk.code import apply as code_apply
|
|
13
13
|
from validio_sdk.code import plan as code_plan
|
|
14
14
|
from validio_sdk.code import scaffold
|
|
15
|
+
from validio_sdk.features import Feature
|
|
15
16
|
from validio_sdk.resource._diff import GraphDiff, ResourceUpdate
|
|
16
|
-
from validio_sdk.resource._resource import
|
|
17
|
+
from validio_sdk.resource._resource import (
|
|
18
|
+
DiffContext,
|
|
19
|
+
Resource,
|
|
20
|
+
ResourceDeprecation,
|
|
21
|
+
ResourceFeatureNotice,
|
|
22
|
+
)
|
|
17
23
|
from validio_sdk.resource._util import SourceSchemaReinference
|
|
18
24
|
from validio_sdk.resource.replacement import (
|
|
19
25
|
ImmutableFieldReplacementReason,
|
|
@@ -21,7 +27,13 @@ from validio_sdk.resource.replacement import (
|
|
|
21
27
|
ReplacementReason,
|
|
22
28
|
)
|
|
23
29
|
|
|
24
|
-
from validio_cli import
|
|
30
|
+
from validio_cli import (
|
|
31
|
+
AsyncTyper,
|
|
32
|
+
ConfigDir,
|
|
33
|
+
Namespace,
|
|
34
|
+
_apply_feature_flags,
|
|
35
|
+
get_client,
|
|
36
|
+
)
|
|
25
37
|
from validio_cli.bin.entities.resources import ResourceNamesToMove, do_move
|
|
26
38
|
from validio_cli.components import BETA_BANNER, proceed_with_operation
|
|
27
39
|
|
|
@@ -31,6 +43,25 @@ MAX_DEPRECATIONS_TO_SHOW = 20
|
|
|
31
43
|
app = AsyncTyper(help="Plan or apply your configuration")
|
|
32
44
|
|
|
33
45
|
|
|
46
|
+
@app.callback()
|
|
47
|
+
def _configure(
|
|
48
|
+
feature: list[Feature] = typer.Option(
|
|
49
|
+
[],
|
|
50
|
+
"--feature",
|
|
51
|
+
help=(
|
|
52
|
+
"Enable an opt-in feature. Repeatable. Features may change or be "
|
|
53
|
+
"removed at any time."
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
all_features_flag: bool = typer.Option(
|
|
57
|
+
False,
|
|
58
|
+
"--all-features",
|
|
59
|
+
help="Enable every opt-in feature.",
|
|
60
|
+
),
|
|
61
|
+
) -> None:
|
|
62
|
+
_apply_feature_flags(feature=feature, all_features_flag=all_features_flag)
|
|
63
|
+
|
|
64
|
+
|
|
34
65
|
class DiffOutput(str, Enum):
|
|
35
66
|
"""Available output formats for the CLI"""
|
|
36
67
|
|
|
@@ -436,6 +467,7 @@ async def _plan(
|
|
|
436
467
|
)
|
|
437
468
|
|
|
438
469
|
_show_deprecations(plan_result.deprecations)
|
|
470
|
+
_show_feature_notices(plan_result.feature_notices)
|
|
439
471
|
|
|
440
472
|
return plan_result
|
|
441
473
|
|
|
@@ -676,6 +708,25 @@ def _show_deprecations(deprecations: list[ResourceDeprecation]) -> None:
|
|
|
676
708
|
print(footer, end="")
|
|
677
709
|
|
|
678
710
|
|
|
711
|
+
def _show_feature_notices(notices: list[ResourceFeatureNotice]) -> None:
|
|
712
|
+
if not notices:
|
|
713
|
+
return
|
|
714
|
+
|
|
715
|
+
title = "⚠️ FEATURES IN USE"
|
|
716
|
+
footer = ""
|
|
717
|
+
|
|
718
|
+
if len(notices) > MAX_DEPRECATIONS_TO_SHOW:
|
|
719
|
+
footer = f"And {len(notices) - MAX_DEPRECATIONS_TO_SHOW} more...\n"
|
|
720
|
+
notices = notices[:MAX_DEPRECATIONS_TO_SHOW]
|
|
721
|
+
|
|
722
|
+
print()
|
|
723
|
+
print(f"\033[93m{title}\033[0m")
|
|
724
|
+
for i, message in enumerate(sorted(notices)):
|
|
725
|
+
print(f"\033[93m{i + 1:>2}. {message}\033[0m")
|
|
726
|
+
|
|
727
|
+
print(footer, end="")
|
|
728
|
+
|
|
729
|
+
|
|
679
730
|
def create_source_schema_reinference(
|
|
680
731
|
schemas_to_update: list[str], update_all_schemas: bool
|
|
681
732
|
) -> SourceSchemaReinference:
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import typer
|
|
2
|
+
from camel_converter import to_snake
|
|
3
|
+
from validio_sdk.exception import ValidioError
|
|
4
|
+
|
|
5
|
+
from validio_cli import (
|
|
6
|
+
APIClient,
|
|
7
|
+
AsyncTyper,
|
|
8
|
+
ConfigDir,
|
|
9
|
+
Identifier,
|
|
10
|
+
Identifiers,
|
|
11
|
+
OutputFormat,
|
|
12
|
+
OutputFormatOption,
|
|
13
|
+
OutputSettings,
|
|
14
|
+
_single_resource_if_specified,
|
|
15
|
+
get_client,
|
|
16
|
+
output_json,
|
|
17
|
+
output_ok_or_error,
|
|
18
|
+
output_text,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
app = AsyncTyper(help="Integrations")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@app.async_command(help="Get integrations")
|
|
25
|
+
async def get(
|
|
26
|
+
config_dir: str = ConfigDir,
|
|
27
|
+
output_format: OutputFormat = OutputFormatOption,
|
|
28
|
+
identifier: str = Identifier,
|
|
29
|
+
) -> None:
|
|
30
|
+
client, _ = get_client(config_dir)
|
|
31
|
+
|
|
32
|
+
integrations = await client.get_integrations(integration_id=identifier)
|
|
33
|
+
|
|
34
|
+
if isinstance(integrations, list):
|
|
35
|
+
integrations = _single_resource_if_specified(integrations, identifier)
|
|
36
|
+
|
|
37
|
+
if output_format == OutputFormat.JSON:
|
|
38
|
+
return output_json(integrations, identifier)
|
|
39
|
+
|
|
40
|
+
return output_text(
|
|
41
|
+
integrations,
|
|
42
|
+
fields={
|
|
43
|
+
"name": OutputSettings(attribute_name="resourceName"),
|
|
44
|
+
"type": OutputSettings(
|
|
45
|
+
attribute_name="__typename",
|
|
46
|
+
reformat=lambda x: to_snake(x.removesuffix("Integration")).upper(),
|
|
47
|
+
),
|
|
48
|
+
"age": OutputSettings.string_as_datetime("createdAt"),
|
|
49
|
+
},
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@app.async_command(help="Delete integration")
|
|
54
|
+
async def delete(
|
|
55
|
+
config_dir: str = ConfigDir,
|
|
56
|
+
output_format: OutputFormat = OutputFormatOption,
|
|
57
|
+
identifiers: list[str] = Identifiers,
|
|
58
|
+
) -> None:
|
|
59
|
+
if not identifiers:
|
|
60
|
+
raise ValidioError("no identifiers are provided")
|
|
61
|
+
|
|
62
|
+
vc, _ = get_client(config_dir)
|
|
63
|
+
|
|
64
|
+
integration_ids = [
|
|
65
|
+
integration_id
|
|
66
|
+
for integration_id in [
|
|
67
|
+
await get_integration_id(vc, identifier) for identifier in identifiers
|
|
68
|
+
]
|
|
69
|
+
if integration_id
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
result = await vc.delete_integrations(integration_ids)
|
|
73
|
+
|
|
74
|
+
if output_format == OutputFormat.JSON:
|
|
75
|
+
return output_json(result)
|
|
76
|
+
|
|
77
|
+
return output_ok_or_error(result)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
async def get_integration_id(vc: APIClient, identifier: str) -> str | None:
|
|
81
|
+
"""
|
|
82
|
+
Ensure the identifier is a resource id.
|
|
83
|
+
|
|
84
|
+
If it doesn't have the expected prefix, do a resource lookup by name.
|
|
85
|
+
"""
|
|
86
|
+
identifier_type = "integration"
|
|
87
|
+
prefix = "INT_"
|
|
88
|
+
|
|
89
|
+
if not identifier:
|
|
90
|
+
print(f"Missing {identifier_type} id or name")
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
if identifier.startswith(prefix):
|
|
94
|
+
return identifier
|
|
95
|
+
|
|
96
|
+
resource = await vc.get_integrations(integration_id=identifier)
|
|
97
|
+
|
|
98
|
+
if resource is None:
|
|
99
|
+
print(f"No {identifier_type} with name or id {identifier} found")
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
if not isinstance(resource, dict):
|
|
103
|
+
raise ValidioError("failed to get integration id")
|
|
104
|
+
|
|
105
|
+
return resource["id"]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
if __name__ == "__main__":
|
|
109
|
+
typer.run(app())
|
|
@@ -8,8 +8,10 @@ import validio_sdk.metadata
|
|
|
8
8
|
from tabulate import tabulate
|
|
9
9
|
from validio_sdk import ValidioError
|
|
10
10
|
from validio_sdk.config import Config
|
|
11
|
+
from validio_sdk.features import Feature
|
|
11
12
|
|
|
12
13
|
import validio_cli.metadata
|
|
14
|
+
from validio_cli import _apply_feature_flags
|
|
13
15
|
from validio_cli.bin.entities import (
|
|
14
16
|
channels,
|
|
15
17
|
code,
|
|
@@ -18,6 +20,7 @@ from validio_cli.bin.entities import (
|
|
|
18
20
|
dbt,
|
|
19
21
|
filters,
|
|
20
22
|
incidents,
|
|
23
|
+
integrations,
|
|
21
24
|
metrics,
|
|
22
25
|
namespaces,
|
|
23
26
|
notification_rules,
|
|
@@ -37,6 +40,26 @@ app = typer.Typer(
|
|
|
37
40
|
rich_markup_mode="rich",
|
|
38
41
|
)
|
|
39
42
|
|
|
43
|
+
|
|
44
|
+
@app.callback()
|
|
45
|
+
def _configure(
|
|
46
|
+
feature: list[Feature] = typer.Option(
|
|
47
|
+
[],
|
|
48
|
+
"--feature",
|
|
49
|
+
help=(
|
|
50
|
+
"Enable an opt-in feature. Repeatable. Features may change or be "
|
|
51
|
+
"removed at any time."
|
|
52
|
+
),
|
|
53
|
+
),
|
|
54
|
+
all_features_flag: bool = typer.Option(
|
|
55
|
+
False,
|
|
56
|
+
"--all-features",
|
|
57
|
+
help="Enable every opt-in feature.",
|
|
58
|
+
),
|
|
59
|
+
) -> None:
|
|
60
|
+
_apply_feature_flags(feature=feature, all_features_flag=all_features_flag)
|
|
61
|
+
|
|
62
|
+
|
|
40
63
|
app.add_typer(channels.app, no_args_is_help=True, name="channels")
|
|
41
64
|
app.add_typer(code.app, no_args_is_help=True, name="code")
|
|
42
65
|
app.add_typer(config.app, no_args_is_help=True, name="config")
|
|
@@ -44,6 +67,7 @@ app.add_typer(credentials.app, no_args_is_help=True, name="credentials")
|
|
|
44
67
|
app.add_typer(dbt.app, no_args_is_help=True, name="dbt")
|
|
45
68
|
app.add_typer(filters.app, no_args_is_help=True, name="filters")
|
|
46
69
|
app.add_typer(incidents.app, no_args_is_help=True, name="incidents")
|
|
70
|
+
app.add_typer(integrations.app, no_args_is_help=True, name="integrations")
|
|
47
71
|
app.add_typer(metrics.app, no_args_is_help=True, name="metrics")
|
|
48
72
|
app.add_typer(namespaces.app, no_args_is_help=True, name="namespaces")
|
|
49
73
|
app.add_typer(resources.app, no_args_is_help=True, name="resources")
|
|
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
|