validio-cli 0.14.0__tar.gz → 0.15.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.14.0 → validio_cli-0.15.0}/PKG-INFO +2 -2
- {validio_cli-0.14.0 → validio_cli-0.15.0}/pyproject.toml +2 -2
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/config.py +4 -1
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/dbt.py +4 -0
- validio_cli-0.15.0/validio_cli/bin/entities/incidents.py +155 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/notification_rules.py +0 -9
- validio_cli-0.14.0/validio_cli/bin/entities/incidents.py +0 -256
- {validio_cli-0.14.0 → validio_cli-0.15.0}/LICENSE +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/README_PUBLIC.md +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/__init__.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/channels.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/code.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/credentials.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/metrics.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/recommendations.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/resources.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/segmentations.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/segments.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/sources.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/users.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/validators.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/entities/windows.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/bin/main.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/components.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/metadata.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/namespace.py +0 -0
- {validio_cli-0.14.0 → validio_cli-0.15.0}/validio_cli/schema.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: validio-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0
|
|
4
4
|
Summary: CLI tool to interact with the Validio platform
|
|
5
5
|
Home-page: https://validio.io/
|
|
6
6
|
License: Apache-2.0
|
|
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
14
14
|
Requires-Dist: camel-converter (>=3.0.0,<4.0.0)
|
|
15
|
-
Requires-Dist: classdiff (
|
|
15
|
+
Requires-Dist: classdiff (==0.4.0)
|
|
16
16
|
Requires-Dist: prompt-toolkit (>=3.0.38,<4.0.0)
|
|
17
17
|
Requires-Dist: pydantic (==2.4.2)
|
|
18
18
|
Requires-Dist: tabulate (>=0.9.0,<0.10.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.15.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,7 +15,7 @@ readme = "README_PUBLIC.md"
|
|
|
15
15
|
[tool.poetry.dependencies]
|
|
16
16
|
python = "^3.10"
|
|
17
17
|
camel-converter = "^3.0.0"
|
|
18
|
-
classdiff = "
|
|
18
|
+
classdiff = "0.4.0"
|
|
19
19
|
validio-sdk = "*"
|
|
20
20
|
typer = { extras = ["all"], version = "^0.7.0" }
|
|
21
21
|
prompt-toolkit = "^3.0.38"
|
|
@@ -77,6 +77,7 @@ def ns(
|
|
|
77
77
|
def get(
|
|
78
78
|
config_dir: str = ConfigDir,
|
|
79
79
|
output_format: OutputFormat = OutputFormatOption,
|
|
80
|
+
show_secrets: bool = False,
|
|
80
81
|
) -> None:
|
|
81
82
|
config_path = Path(config_dir) if config_dir is not None else None
|
|
82
83
|
|
|
@@ -109,7 +110,9 @@ def get(
|
|
|
109
110
|
"default_namespace": validio_config.default_namespace,
|
|
110
111
|
"endpoint": validio_config.endpoint,
|
|
111
112
|
"access_key": validio_config.access_key,
|
|
112
|
-
"access_secret": validio_config.
|
|
113
|
+
"access_secret": validio_config._access_secret
|
|
114
|
+
if show_secrets
|
|
115
|
+
else validio_config.access_secret,
|
|
113
116
|
}
|
|
114
117
|
|
|
115
118
|
if output_format == OutputFormat.JSON:
|
|
@@ -19,6 +19,9 @@ async def upload(
|
|
|
19
19
|
namespace: str = Namespace(),
|
|
20
20
|
credential_id: str = typer.Option(..., help="Credential name or ID"),
|
|
21
21
|
manifest: Path = typer.Option(..., help="Path to the manifest file"),
|
|
22
|
+
job_name: str = typer.Option(
|
|
23
|
+
..., help="The job that the dbt execution belongs to, e.g. `staging-pipeline`"
|
|
24
|
+
),
|
|
22
25
|
run_results: Path = typer.Option(help="Path to the run results file", default=None),
|
|
23
26
|
) -> None:
|
|
24
27
|
vc, cfg = await get_client_and_config(config_dir)
|
|
@@ -46,6 +49,7 @@ async def upload(
|
|
|
46
49
|
credential_id=resolved_credential_id,
|
|
47
50
|
manifest=json.dumps(trimmed_manifest),
|
|
48
51
|
run_results=run_results_content,
|
|
52
|
+
job_name=job_name,
|
|
49
53
|
)
|
|
50
54
|
)
|
|
51
55
|
return print("dbt artifact uploaded successfully")
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
from datetime import datetime, timedelta
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import typer
|
|
5
|
+
from validio_sdk import ValidioError
|
|
6
|
+
from validio_sdk.graphql_client import (
|
|
7
|
+
GetSourceIncidentsSource,
|
|
8
|
+
GetValidatorIncidentsValidator,
|
|
9
|
+
)
|
|
10
|
+
from validio_sdk.graphql_client.input_types import TimeRangeInput
|
|
11
|
+
|
|
12
|
+
from validio_cli import (
|
|
13
|
+
AsyncTyper,
|
|
14
|
+
ConfigDir,
|
|
15
|
+
Namespace,
|
|
16
|
+
OutputFormat,
|
|
17
|
+
OutputFormatOption,
|
|
18
|
+
OutputSettings,
|
|
19
|
+
_format_relative_time,
|
|
20
|
+
get_client_and_config,
|
|
21
|
+
output_json,
|
|
22
|
+
output_text,
|
|
23
|
+
)
|
|
24
|
+
from validio_cli.bin.entities import sources, validators
|
|
25
|
+
|
|
26
|
+
app = AsyncTyper(help="Incidents from validators")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@app.async_command(
|
|
30
|
+
help="""List all incidents.
|
|
31
|
+
|
|
32
|
+
By default you will get incidents from the last hour. You can specify a time
|
|
33
|
+
range for when the incident occurred by specifying when the incident ended.
|
|
34
|
+
|
|
35
|
+
You can list incidents in different ways:
|
|
36
|
+
|
|
37
|
+
* Listing all incidents
|
|
38
|
+
|
|
39
|
+
* Listing all source incidents for a specific source with --source
|
|
40
|
+
|
|
41
|
+
* Listing all incidents for a specific validator with --validator
|
|
42
|
+
|
|
43
|
+
* Listing all incidents for a specific segment with --segment
|
|
44
|
+
|
|
45
|
+
* Listing all incidents for a specific validator and segment with --validator
|
|
46
|
+
and --segment together
|
|
47
|
+
"""
|
|
48
|
+
)
|
|
49
|
+
async def get(
|
|
50
|
+
config_dir: str = ConfigDir,
|
|
51
|
+
output_format: OutputFormat = OutputFormatOption,
|
|
52
|
+
namespace: str = Namespace(),
|
|
53
|
+
ended_before: datetime = typer.Option(
|
|
54
|
+
datetime.utcnow(),
|
|
55
|
+
help="The incident ended before this timestamp",
|
|
56
|
+
),
|
|
57
|
+
ended_after: datetime = typer.Option(
|
|
58
|
+
(datetime.utcnow() - timedelta(hours=1)),
|
|
59
|
+
help="The incident ended after this timestamp",
|
|
60
|
+
),
|
|
61
|
+
validator: str = typer.Option(None, help="Validator to fetch incidents for"),
|
|
62
|
+
segment: str = typer.Option(None, help="Segment to fetch incidents for"),
|
|
63
|
+
source: str = typer.Option(None, help="Source to fetch incidents for"),
|
|
64
|
+
) -> None:
|
|
65
|
+
vc, cfg = await get_client_and_config(config_dir)
|
|
66
|
+
|
|
67
|
+
if validator is not None:
|
|
68
|
+
validator_id = await validators.get_validator_id(vc, cfg, validator, namespace)
|
|
69
|
+
if validator_id is None:
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
if source is not None:
|
|
73
|
+
source_id = await sources.get_source_id(vc, cfg, source, namespace)
|
|
74
|
+
if source_id is None:
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
# TODO(UI-2006): These should all support namespace
|
|
78
|
+
|
|
79
|
+
incidents: (None | GetValidatorIncidentsValidator | GetSourceIncidentsSource) = None
|
|
80
|
+
|
|
81
|
+
if validator:
|
|
82
|
+
incidents = await vc.get_validator_incidents(
|
|
83
|
+
id=validator_id,
|
|
84
|
+
range=TimeRangeInput(
|
|
85
|
+
start=ended_after,
|
|
86
|
+
end=ended_before,
|
|
87
|
+
),
|
|
88
|
+
segment_id=segment,
|
|
89
|
+
)
|
|
90
|
+
elif source:
|
|
91
|
+
incidents = await vc.get_source_incidents(
|
|
92
|
+
id=source_id,
|
|
93
|
+
range=TimeRangeInput(
|
|
94
|
+
start=ended_after,
|
|
95
|
+
end=ended_before,
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
else:
|
|
99
|
+
raise ValidioError(
|
|
100
|
+
"You need to specify one of --validator and/or --segment or --source"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
if not incidents:
|
|
104
|
+
return output_text(None, {})
|
|
105
|
+
|
|
106
|
+
if output_format == OutputFormat.JSON:
|
|
107
|
+
return output_json(incidents)
|
|
108
|
+
|
|
109
|
+
return output_text(
|
|
110
|
+
incidents.incidents,
|
|
111
|
+
fields={
|
|
112
|
+
"operator": OutputSettings(
|
|
113
|
+
attribute_name="metric",
|
|
114
|
+
reformat=calculate_operator,
|
|
115
|
+
),
|
|
116
|
+
"bound": OutputSettings(
|
|
117
|
+
attribute_name="metric",
|
|
118
|
+
reformat=calculate_bound,
|
|
119
|
+
),
|
|
120
|
+
"value": OutputSettings(
|
|
121
|
+
attribute_name="metric",
|
|
122
|
+
reformat=lambda x: x.value,
|
|
123
|
+
),
|
|
124
|
+
"age": OutputSettings(
|
|
125
|
+
attribute_name="metric",
|
|
126
|
+
reformat=lambda x: _format_relative_time(x.end_time),
|
|
127
|
+
),
|
|
128
|
+
},
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def calculate_operator(item: Any) -> str:
|
|
133
|
+
type_ = item.typename__[len("ValidatorMetricWith") :]
|
|
134
|
+
if type_ == "DynamicThreshold":
|
|
135
|
+
operator = item.decision_bounds_type
|
|
136
|
+
else:
|
|
137
|
+
operator = item.operator
|
|
138
|
+
|
|
139
|
+
return f"{type_}/{operator}"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def calculate_bound(item: Any) -> str:
|
|
143
|
+
type_ = item.typename__[len("ValidatorMetricWith") :]
|
|
144
|
+
if type_ == "DynamicThreshold":
|
|
145
|
+
bound = f"{item.lower_bound:.2f} - {item.upper_bound:.2f}"
|
|
146
|
+
elif type_ == "FixedThreshold":
|
|
147
|
+
bound = item.bound
|
|
148
|
+
else:
|
|
149
|
+
bound = "-"
|
|
150
|
+
|
|
151
|
+
return bound
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
if __name__ == "__main__":
|
|
155
|
+
typer.run(app())
|
|
@@ -28,9 +28,6 @@ async def get(
|
|
|
28
28
|
output_format: OutputFormat = OutputFormatOption,
|
|
29
29
|
namespace: str = Namespace(),
|
|
30
30
|
identifier: str = Identifier,
|
|
31
|
-
source: str = typer.Option(
|
|
32
|
-
None, help="List notification rules for this source (ID)"
|
|
33
|
-
),
|
|
34
31
|
) -> None:
|
|
35
32
|
vc, cfg = await get_client_and_config(config_dir)
|
|
36
33
|
|
|
@@ -46,12 +43,6 @@ async def get(
|
|
|
46
43
|
filter=ResourceFilter(resource_namespace=get_namespace(namespace, cfg))
|
|
47
44
|
)
|
|
48
45
|
|
|
49
|
-
notification_rules = [
|
|
50
|
-
nr
|
|
51
|
-
for nr in notification_rules
|
|
52
|
-
if source is None or (nr is not None and source in nr.sources)
|
|
53
|
-
]
|
|
54
|
-
|
|
55
46
|
# TODO(UI-2311): Fully support list/get/get_by_resource_name
|
|
56
47
|
notification_rules = _single_resource_if_specified(notification_rules, identifier)
|
|
57
48
|
|
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from datetime import datetime, timedelta
|
|
3
|
-
from typing import Any
|
|
4
|
-
|
|
5
|
-
import typer
|
|
6
|
-
from validio_sdk import ValidioError
|
|
7
|
-
from validio_sdk.graphql_client import (
|
|
8
|
-
GetSegmentIncidentsSegmentIncidents,
|
|
9
|
-
GetSourceIncidentsSourceIncidentsSegmentLimitExceededNotification,
|
|
10
|
-
GetValidatorIncidentsValidatorIncidents,
|
|
11
|
-
GetValidatorSegmentIncidentsValidatorSegmentIncidents,
|
|
12
|
-
)
|
|
13
|
-
from validio_sdk.graphql_client.input_types import (
|
|
14
|
-
SegmentIncidentsInput,
|
|
15
|
-
SourceIncidentsInput,
|
|
16
|
-
TimeRangeInput,
|
|
17
|
-
ValidatorIncidentsInput,
|
|
18
|
-
ValidatorSegmentIncidentsInput,
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
from validio_cli import (
|
|
22
|
-
AsyncTyper,
|
|
23
|
-
ConfigDir,
|
|
24
|
-
Namespace,
|
|
25
|
-
OutputFormat,
|
|
26
|
-
OutputFormatOption,
|
|
27
|
-
OutputSettings,
|
|
28
|
-
_format_relative_time,
|
|
29
|
-
get_client_and_config,
|
|
30
|
-
output_json,
|
|
31
|
-
output_text,
|
|
32
|
-
)
|
|
33
|
-
from validio_cli.bin.entities import sources, validators
|
|
34
|
-
|
|
35
|
-
app = AsyncTyper(help="Incidents from validators")
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
@app.async_command(
|
|
39
|
-
help="""List all incidents.
|
|
40
|
-
|
|
41
|
-
By default you will get incidents from the last hour. You can specify a time
|
|
42
|
-
range for when the incident occurred by specifying when the incident ended.
|
|
43
|
-
|
|
44
|
-
You can list incidents in different ways:
|
|
45
|
-
|
|
46
|
-
* Listing all incidents
|
|
47
|
-
|
|
48
|
-
* Listing all source incidents for a specific source with --source
|
|
49
|
-
|
|
50
|
-
* Listing all incidents for a specific validator with --validator
|
|
51
|
-
|
|
52
|
-
* Listing all incidents for a specific segment with --segment
|
|
53
|
-
|
|
54
|
-
* Listing all incidents for a specific validator and segment with --validator
|
|
55
|
-
and --segment together
|
|
56
|
-
"""
|
|
57
|
-
)
|
|
58
|
-
async def get(
|
|
59
|
-
config_dir: str = ConfigDir,
|
|
60
|
-
output_format: OutputFormat = OutputFormatOption,
|
|
61
|
-
namespace: str = Namespace(),
|
|
62
|
-
ended_before: datetime = typer.Option(
|
|
63
|
-
datetime.utcnow(),
|
|
64
|
-
help="The incident ended before this timestamp",
|
|
65
|
-
),
|
|
66
|
-
ended_after: datetime = typer.Option(
|
|
67
|
-
(datetime.utcnow() - timedelta(hours=1)),
|
|
68
|
-
help="The incident ended after this timestamp",
|
|
69
|
-
),
|
|
70
|
-
validator: str = typer.Option(None, help="Validator to fetch incidents for"),
|
|
71
|
-
segment: str = typer.Option(None, help="Segment to fetch incidents for"),
|
|
72
|
-
source: str = typer.Option(None, help="Source to fetch incidents for"),
|
|
73
|
-
) -> None:
|
|
74
|
-
vc, cfg = await get_client_and_config(config_dir)
|
|
75
|
-
|
|
76
|
-
if validator is not None:
|
|
77
|
-
validator_id = await validators.get_validator_id(vc, cfg, validator, namespace)
|
|
78
|
-
if validator_id is None:
|
|
79
|
-
return None
|
|
80
|
-
|
|
81
|
-
if source is not None:
|
|
82
|
-
source_id = await sources.get_source_id(vc, cfg, source, namespace)
|
|
83
|
-
if source_id is None:
|
|
84
|
-
return None
|
|
85
|
-
|
|
86
|
-
# TODO(UI-2006): These should all support namespace
|
|
87
|
-
|
|
88
|
-
incidents: (
|
|
89
|
-
None
|
|
90
|
-
| list[GetValidatorIncidentsValidatorIncidents]
|
|
91
|
-
| list[GetValidatorSegmentIncidentsValidatorSegmentIncidents]
|
|
92
|
-
| list[GetSegmentIncidentsSegmentIncidents]
|
|
93
|
-
) = None
|
|
94
|
-
|
|
95
|
-
if validator and segment:
|
|
96
|
-
incidents = await vc.get_validator_segment_incidents(
|
|
97
|
-
ValidatorSegmentIncidentsInput(
|
|
98
|
-
time_range=TimeRangeInput(
|
|
99
|
-
start=ended_after,
|
|
100
|
-
end=ended_before,
|
|
101
|
-
),
|
|
102
|
-
validator_id=validator_id,
|
|
103
|
-
segment_id=segment,
|
|
104
|
-
)
|
|
105
|
-
)
|
|
106
|
-
elif validator:
|
|
107
|
-
incidents = await vc.get_validator_incidents(
|
|
108
|
-
ValidatorIncidentsInput(
|
|
109
|
-
time_range=TimeRangeInput(
|
|
110
|
-
start=ended_after,
|
|
111
|
-
end=ended_before,
|
|
112
|
-
),
|
|
113
|
-
validator_id=validator_id,
|
|
114
|
-
)
|
|
115
|
-
)
|
|
116
|
-
elif segment:
|
|
117
|
-
incidents = await vc.get_segment_incidents(
|
|
118
|
-
SegmentIncidentsInput(
|
|
119
|
-
time_range=TimeRangeInput(
|
|
120
|
-
start=ended_after,
|
|
121
|
-
end=ended_before,
|
|
122
|
-
),
|
|
123
|
-
segment_id=segment,
|
|
124
|
-
)
|
|
125
|
-
)
|
|
126
|
-
elif source:
|
|
127
|
-
# Since source incidents looks completely different we hand them off to
|
|
128
|
-
# a separate function, we can't re-use any of the rendering.
|
|
129
|
-
return _output_text_source_incidents(
|
|
130
|
-
output_format,
|
|
131
|
-
await vc.get_source_incidents(
|
|
132
|
-
SourceIncidentsInput(
|
|
133
|
-
time_range=TimeRangeInput(
|
|
134
|
-
start=ended_after,
|
|
135
|
-
end=ended_before,
|
|
136
|
-
),
|
|
137
|
-
source_id=source_id,
|
|
138
|
-
)
|
|
139
|
-
),
|
|
140
|
-
)
|
|
141
|
-
else:
|
|
142
|
-
raise ValidioError(
|
|
143
|
-
"You need to specify one of --validator and/or --segment or --source"
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
if output_format == OutputFormat.JSON:
|
|
147
|
-
return output_json(incidents)
|
|
148
|
-
|
|
149
|
-
return output_text(
|
|
150
|
-
incidents,
|
|
151
|
-
fields={
|
|
152
|
-
"operator": OutputSettings(
|
|
153
|
-
attribute_name="metric",
|
|
154
|
-
reformat=calculate_operator,
|
|
155
|
-
),
|
|
156
|
-
"bound": OutputSettings(
|
|
157
|
-
attribute_name="metric",
|
|
158
|
-
reformat=calculate_bound,
|
|
159
|
-
),
|
|
160
|
-
"value": OutputSettings(
|
|
161
|
-
attribute_name="metric",
|
|
162
|
-
reformat=lambda x: x.value,
|
|
163
|
-
),
|
|
164
|
-
"age": OutputSettings(
|
|
165
|
-
attribute_name="metric",
|
|
166
|
-
reformat=lambda x: _format_relative_time(x.end_time),
|
|
167
|
-
),
|
|
168
|
-
},
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def _output_text_source_incidents(
|
|
173
|
-
output_format: OutputFormat, incidents: list[Any]
|
|
174
|
-
) -> None:
|
|
175
|
-
if output_format == OutputFormat.JSON:
|
|
176
|
-
return output_json(incidents)
|
|
177
|
-
|
|
178
|
-
@dataclass
|
|
179
|
-
class SchemaChange:
|
|
180
|
-
field: str
|
|
181
|
-
change_type: str
|
|
182
|
-
old_value: str
|
|
183
|
-
new_value: str
|
|
184
|
-
|
|
185
|
-
change_type_to_key = {
|
|
186
|
-
"Nullability": "nullable",
|
|
187
|
-
"JtdType": "type",
|
|
188
|
-
"UnderlyingType": "underlying_type",
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
changes = []
|
|
192
|
-
for item in incidents:
|
|
193
|
-
# TODO: We only show schema changes for now
|
|
194
|
-
if item.typename__ != "SchemaChangeNotification":
|
|
195
|
-
continue
|
|
196
|
-
|
|
197
|
-
for field, field_changes in item.payload.items():
|
|
198
|
-
for ct in field_changes["change_types"]:
|
|
199
|
-
k = change_type_to_key.get(ct)
|
|
200
|
-
|
|
201
|
-
changes.append(
|
|
202
|
-
SchemaChange(
|
|
203
|
-
field=field,
|
|
204
|
-
change_type=ct,
|
|
205
|
-
old_value=field_changes["old"][k] if k else "-",
|
|
206
|
-
new_value=field_changes["new"][k] if k else "-",
|
|
207
|
-
)
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
return output_text(
|
|
211
|
-
changes,
|
|
212
|
-
fields={
|
|
213
|
-
"field": None,
|
|
214
|
-
"change_type": None,
|
|
215
|
-
"old_value": None,
|
|
216
|
-
"new_value": None,
|
|
217
|
-
},
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def calculate_operator(item: Any) -> str:
|
|
222
|
-
type_ = item.typename__[len("ValidatorMetricWith") :]
|
|
223
|
-
if type_ == "DynamicThreshold":
|
|
224
|
-
operator = item.decision_bounds_type
|
|
225
|
-
else:
|
|
226
|
-
operator = item.operator
|
|
227
|
-
|
|
228
|
-
return f"{type_}/{operator}"
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
def calculate_bound(item: Any) -> str:
|
|
232
|
-
type_ = item.typename__[len("ValidatorMetricWith") :]
|
|
233
|
-
if type_ == "DynamicThreshold":
|
|
234
|
-
bound = f"{item.lower_bound:.2f} - {item.upper_bound:.2f}"
|
|
235
|
-
elif type_ == "FixedThreshold":
|
|
236
|
-
bound = item.bound
|
|
237
|
-
else:
|
|
238
|
-
bound = "-"
|
|
239
|
-
|
|
240
|
-
return bound
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
def _output_text_source_incidents_segment_limit_exceeded(
|
|
244
|
-
incidents: list[GetSourceIncidentsSourceIncidentsSegmentLimitExceededNotification],
|
|
245
|
-
) -> None:
|
|
246
|
-
return output_text(
|
|
247
|
-
incidents,
|
|
248
|
-
fields={
|
|
249
|
-
"limit": None,
|
|
250
|
-
"age": OutputSettings(attribute_name="created_at"),
|
|
251
|
-
},
|
|
252
|
-
)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if __name__ == "__main__":
|
|
256
|
-
typer.run(app())
|
|
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
|