validio-cli 8.2.1__tar.gz → 9.0.6__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.
Files changed (28) hide show
  1. {validio_cli-8.2.1 → validio_cli-9.0.6}/PKG-INFO +1 -1
  2. {validio_cli-8.2.1 → validio_cli-9.0.6}/pyproject.toml +1 -1
  3. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/__init__.py +20 -0
  4. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/code.py +53 -2
  5. validio_cli-9.0.6/validio_cli/bin/entities/integrations.py +109 -0
  6. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/main.py +24 -0
  7. {validio_cli-8.2.1 → validio_cli-9.0.6}/LICENSE +0 -0
  8. {validio_cli-8.2.1 → validio_cli-9.0.6}/README_PUBLIC.md +0 -0
  9. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/channels.py +0 -0
  10. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/config.py +0 -0
  11. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/credentials.py +0 -0
  12. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/dbt.py +0 -0
  13. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/filters.py +0 -0
  14. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/incidents.py +0 -0
  15. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/metrics.py +0 -0
  16. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/namespaces.py +0 -0
  17. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/notification_rules.py +0 -0
  18. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/resources.py +0 -0
  19. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/segmentations.py +0 -0
  20. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/segments.py +0 -0
  21. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/sources.py +0 -0
  22. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/users.py +0 -0
  23. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/validators.py +0 -0
  24. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/bin/entities/windows.py +0 -0
  25. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/components.py +0 -0
  26. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/metadata.py +0 -0
  27. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/namespace.py +0 -0
  28. {validio_cli-8.2.1 → validio_cli-9.0.6}/validio_cli/schema.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: validio-cli
3
- Version: 8.2.1
3
+ Version: 9.0.6
4
4
  Summary: CLI tool to interact with the Validio platform
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -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 = "8.2.1"
6
+ version = "9.0.6"
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 DiffContext, Resource, ResourceDeprecation
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 AsyncTyper, ConfigDir, Namespace, get_client
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