google-analytics-cli 0.1.0__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.
- ga_cli/__init__.py +8 -0
- ga_cli/api/__init__.py +0 -0
- ga_cli/api/client.py +142 -0
- ga_cli/auth/__init__.py +35 -0
- ga_cli/auth/credentials.py +126 -0
- ga_cli/auth/oauth.py +322 -0
- ga_cli/auth/service_account.py +155 -0
- ga_cli/commands/__init__.py +0 -0
- ga_cli/commands/access_bindings.py +254 -0
- ga_cli/commands/access_reports.py +201 -0
- ga_cli/commands/account_summaries.py +68 -0
- ga_cli/commands/accounts.py +297 -0
- ga_cli/commands/agent_cmd.py +776 -0
- ga_cli/commands/annotations.py +264 -0
- ga_cli/commands/audiences.py +223 -0
- ga_cli/commands/auth_cmd.py +205 -0
- ga_cli/commands/bigquery_links.py +309 -0
- ga_cli/commands/calculated_metrics.py +312 -0
- ga_cli/commands/channel_groups.py +223 -0
- ga_cli/commands/completions_cmd.py +55 -0
- ga_cli/commands/config_cmd.py +113 -0
- ga_cli/commands/custom_dimensions.py +272 -0
- ga_cli/commands/custom_metrics.py +305 -0
- ga_cli/commands/data_retention.py +153 -0
- ga_cli/commands/data_streams.py +277 -0
- ga_cli/commands/event_create_rules.py +250 -0
- ga_cli/commands/event_edit_rules.py +292 -0
- ga_cli/commands/firebase_links.py +142 -0
- ga_cli/commands/google_ads_links.py +225 -0
- ga_cli/commands/key_events.py +269 -0
- ga_cli/commands/mp_secrets.py +265 -0
- ga_cli/commands/properties.py +330 -0
- ga_cli/commands/property_settings.py +287 -0
- ga_cli/commands/reports.py +726 -0
- ga_cli/commands/upgrade_cmd.py +148 -0
- ga_cli/config/__init__.py +0 -0
- ga_cli/config/constants.py +61 -0
- ga_cli/config/store.py +115 -0
- ga_cli/main.py +110 -0
- ga_cli/utils/__init__.py +20 -0
- ga_cli/utils/describe.py +129 -0
- ga_cli/utils/dry_run.py +40 -0
- ga_cli/utils/errors.py +150 -0
- ga_cli/utils/output.py +209 -0
- ga_cli/utils/pagination.py +93 -0
- google_analytics_cli-0.1.0.dist-info/METADATA +321 -0
- google_analytics_cli-0.1.0.dist-info/RECORD +49 -0
- google_analytics_cli-0.1.0.dist-info/WHEEL +4 -0
- google_analytics_cli-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
"""Data stream management commands."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import questionary
|
|
6
|
+
import typer
|
|
7
|
+
|
|
8
|
+
from ..api.client import get_admin_client
|
|
9
|
+
from ..config.store import get_effective_value
|
|
10
|
+
from ..utils import (
|
|
11
|
+
handle_dry_run,
|
|
12
|
+
handle_error,
|
|
13
|
+
info,
|
|
14
|
+
output,
|
|
15
|
+
require_options,
|
|
16
|
+
resolve_output_format,
|
|
17
|
+
success,
|
|
18
|
+
)
|
|
19
|
+
from ..utils.pagination import paginate_all
|
|
20
|
+
|
|
21
|
+
data_streams_app = typer.Typer(
|
|
22
|
+
name="data-streams", help="Manage GA4 data streams", no_args_is_help=True
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Stream types that require additional configuration
|
|
26
|
+
_WEB_STREAM = "WEB_DATA_STREAM"
|
|
27
|
+
_ANDROID_STREAM = "ANDROID_APP_DATA_STREAM"
|
|
28
|
+
_IOS_STREAM = "IOS_APP_DATA_STREAM"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@data_streams_app.command("list")
|
|
32
|
+
def list_cmd(
|
|
33
|
+
property_id: Optional[str] = typer.Option(
|
|
34
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
35
|
+
),
|
|
36
|
+
output_format: Optional[str] = typer.Option(
|
|
37
|
+
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
38
|
+
),
|
|
39
|
+
):
|
|
40
|
+
"""List data streams for a property."""
|
|
41
|
+
try:
|
|
42
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
43
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
44
|
+
effective_format = resolve_output_format(output_format)
|
|
45
|
+
|
|
46
|
+
admin = get_admin_client()
|
|
47
|
+
streams = paginate_all(
|
|
48
|
+
lambda **kw: admin.properties()
|
|
49
|
+
.dataStreams()
|
|
50
|
+
.list(parent=f"properties/{effective_property}", **kw)
|
|
51
|
+
.execute(),
|
|
52
|
+
"dataStreams",
|
|
53
|
+
pageSize=200,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
output(
|
|
57
|
+
streams,
|
|
58
|
+
effective_format,
|
|
59
|
+
columns=["name", "type", "displayName", "createTime"],
|
|
60
|
+
headers=["Resource Name", "Type", "Display Name", "Created"],
|
|
61
|
+
)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
handle_error(e)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@data_streams_app.command("get")
|
|
67
|
+
def get_cmd(
|
|
68
|
+
property_id: Optional[str] = typer.Option(
|
|
69
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
70
|
+
),
|
|
71
|
+
stream_id: str = typer.Option(
|
|
72
|
+
..., "--stream-id", "-s", help="Data Stream ID"
|
|
73
|
+
),
|
|
74
|
+
output_format: Optional[str] = typer.Option(
|
|
75
|
+
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
76
|
+
),
|
|
77
|
+
):
|
|
78
|
+
"""Get data stream details."""
|
|
79
|
+
try:
|
|
80
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
81
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
82
|
+
effective_format = resolve_output_format(output_format)
|
|
83
|
+
|
|
84
|
+
admin = get_admin_client()
|
|
85
|
+
stream = (
|
|
86
|
+
admin.properties()
|
|
87
|
+
.dataStreams()
|
|
88
|
+
.get(
|
|
89
|
+
name=f"properties/{effective_property}/dataStreams/{stream_id}",
|
|
90
|
+
)
|
|
91
|
+
.execute()
|
|
92
|
+
)
|
|
93
|
+
output(stream, effective_format)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
handle_error(e)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@data_streams_app.command("create")
|
|
99
|
+
def create_cmd(
|
|
100
|
+
property_id: Optional[str] = typer.Option(
|
|
101
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
102
|
+
),
|
|
103
|
+
display_name: str = typer.Option(
|
|
104
|
+
..., "--display-name", help="Stream display name"
|
|
105
|
+
),
|
|
106
|
+
stream_type: str = typer.Option(
|
|
107
|
+
_WEB_STREAM,
|
|
108
|
+
"--type",
|
|
109
|
+
"-t",
|
|
110
|
+
help="Stream type: WEB_DATA_STREAM, ANDROID_APP_DATA_STREAM, IOS_APP_DATA_STREAM",
|
|
111
|
+
),
|
|
112
|
+
url: Optional[str] = typer.Option(
|
|
113
|
+
None, "--url", help="Default URI (required for web streams)"
|
|
114
|
+
),
|
|
115
|
+
bundle_id: Optional[str] = typer.Option(
|
|
116
|
+
None, "--bundle-id", help="App bundle ID (required for app streams)"
|
|
117
|
+
),
|
|
118
|
+
dry_run: bool = typer.Option(
|
|
119
|
+
False, "--dry-run", help="Preview the request without executing"
|
|
120
|
+
),
|
|
121
|
+
output_format: Optional[str] = typer.Option(
|
|
122
|
+
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
123
|
+
),
|
|
124
|
+
):
|
|
125
|
+
"""Create a new data stream."""
|
|
126
|
+
try:
|
|
127
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
128
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
129
|
+
effective_format = resolve_output_format(output_format)
|
|
130
|
+
|
|
131
|
+
body = {
|
|
132
|
+
"displayName": display_name,
|
|
133
|
+
"type": stream_type,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
# Validate and add type-specific data
|
|
137
|
+
if stream_type == _WEB_STREAM:
|
|
138
|
+
if not url:
|
|
139
|
+
raise typer.BadParameter(
|
|
140
|
+
"--url is required for WEB_DATA_STREAM type"
|
|
141
|
+
)
|
|
142
|
+
body["webStreamData"] = {"defaultUri": url}
|
|
143
|
+
elif stream_type == _ANDROID_STREAM:
|
|
144
|
+
if not bundle_id:
|
|
145
|
+
raise typer.BadParameter(
|
|
146
|
+
"--bundle-id is required for ANDROID_APP_DATA_STREAM type"
|
|
147
|
+
)
|
|
148
|
+
body["androidAppStreamData"] = {"packageName": bundle_id}
|
|
149
|
+
elif stream_type == _IOS_STREAM:
|
|
150
|
+
if not bundle_id:
|
|
151
|
+
raise typer.BadParameter(
|
|
152
|
+
"--bundle-id is required for IOS_APP_DATA_STREAM type"
|
|
153
|
+
)
|
|
154
|
+
body["iosAppStreamData"] = {"bundleId": bundle_id}
|
|
155
|
+
|
|
156
|
+
if dry_run:
|
|
157
|
+
handle_dry_run("create", "POST", f"properties/{effective_property}", body)
|
|
158
|
+
|
|
159
|
+
admin = get_admin_client()
|
|
160
|
+
stream = (
|
|
161
|
+
admin.properties()
|
|
162
|
+
.dataStreams()
|
|
163
|
+
.create(parent=f"properties/{effective_property}", body=body)
|
|
164
|
+
.execute()
|
|
165
|
+
)
|
|
166
|
+
output(stream, effective_format)
|
|
167
|
+
except (typer.BadParameter, typer.Exit):
|
|
168
|
+
raise
|
|
169
|
+
except Exception as e:
|
|
170
|
+
handle_error(e)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@data_streams_app.command("update")
|
|
174
|
+
def update_cmd(
|
|
175
|
+
property_id: Optional[str] = typer.Option(
|
|
176
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
177
|
+
),
|
|
178
|
+
stream_id: str = typer.Option(
|
|
179
|
+
..., "--stream-id", "-s", help="Data Stream ID"
|
|
180
|
+
),
|
|
181
|
+
display_name: Optional[str] = typer.Option(
|
|
182
|
+
None, "--display-name", help="New display name"
|
|
183
|
+
),
|
|
184
|
+
dry_run: bool = typer.Option(
|
|
185
|
+
False, "--dry-run", help="Preview the request without executing"
|
|
186
|
+
),
|
|
187
|
+
output_format: Optional[str] = typer.Option(
|
|
188
|
+
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
189
|
+
),
|
|
190
|
+
):
|
|
191
|
+
"""Update a data stream."""
|
|
192
|
+
try:
|
|
193
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
194
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
195
|
+
effective_format = resolve_output_format(output_format)
|
|
196
|
+
|
|
197
|
+
field_map = {
|
|
198
|
+
"displayName": display_name,
|
|
199
|
+
}
|
|
200
|
+
body = {k: v for k, v in field_map.items() if v is not None}
|
|
201
|
+
|
|
202
|
+
if not body:
|
|
203
|
+
raise typer.BadParameter(
|
|
204
|
+
"At least one of --display-name must be specified."
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
update_mask = ",".join(body.keys())
|
|
208
|
+
|
|
209
|
+
if dry_run:
|
|
210
|
+
handle_dry_run(
|
|
211
|
+
"update", "PATCH",
|
|
212
|
+
f"properties/{effective_property}/dataStreams/{stream_id}",
|
|
213
|
+
body, update_mask=update_mask,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
admin = get_admin_client()
|
|
217
|
+
stream = (
|
|
218
|
+
admin.properties()
|
|
219
|
+
.dataStreams()
|
|
220
|
+
.patch(
|
|
221
|
+
name=f"properties/{effective_property}/dataStreams/{stream_id}",
|
|
222
|
+
body=body,
|
|
223
|
+
updateMask=update_mask,
|
|
224
|
+
)
|
|
225
|
+
.execute()
|
|
226
|
+
)
|
|
227
|
+
output(stream, effective_format)
|
|
228
|
+
except (typer.BadParameter, typer.Exit):
|
|
229
|
+
raise
|
|
230
|
+
except Exception as e:
|
|
231
|
+
handle_error(e)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
@data_streams_app.command("delete")
|
|
235
|
+
def delete_cmd(
|
|
236
|
+
property_id: Optional[str] = typer.Option(
|
|
237
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
238
|
+
),
|
|
239
|
+
stream_id: str = typer.Option(
|
|
240
|
+
..., "--stream-id", "-s", help="Data Stream ID"
|
|
241
|
+
),
|
|
242
|
+
yes: bool = typer.Option(
|
|
243
|
+
False, "--yes", "-y", help="Skip confirmation prompt"
|
|
244
|
+
),
|
|
245
|
+
dry_run: bool = typer.Option(
|
|
246
|
+
False, "--dry-run", help="Preview the request without executing"
|
|
247
|
+
),
|
|
248
|
+
):
|
|
249
|
+
"""Delete a data stream."""
|
|
250
|
+
try:
|
|
251
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
252
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
253
|
+
|
|
254
|
+
if dry_run:
|
|
255
|
+
handle_dry_run(
|
|
256
|
+
"delete", "DELETE",
|
|
257
|
+
f"properties/{effective_property}/dataStreams/{stream_id}",
|
|
258
|
+
None,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
if not yes:
|
|
262
|
+
confirmed = questionary.confirm(
|
|
263
|
+
f"Delete data stream {stream_id}? This cannot be undone."
|
|
264
|
+
).ask()
|
|
265
|
+
if not confirmed:
|
|
266
|
+
info("Cancelled.")
|
|
267
|
+
raise typer.Exit()
|
|
268
|
+
|
|
269
|
+
admin = get_admin_client()
|
|
270
|
+
admin.properties().dataStreams().delete(
|
|
271
|
+
name=f"properties/{effective_property}/dataStreams/{stream_id}",
|
|
272
|
+
).execute()
|
|
273
|
+
success(f"Data stream {stream_id} deleted.")
|
|
274
|
+
except typer.Exit:
|
|
275
|
+
raise
|
|
276
|
+
except Exception as e:
|
|
277
|
+
handle_error(e)
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"""Event create rule management commands."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
import questionary
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from ..api.client import get_admin_alpha_client
|
|
11
|
+
from ..config.store import get_effective_value
|
|
12
|
+
from ..utils import handle_error, info, output, require_options, resolve_output_format, success
|
|
13
|
+
from ..utils.pagination import paginate_all
|
|
14
|
+
|
|
15
|
+
event_create_rules_app = typer.Typer(
|
|
16
|
+
name="event-create-rules",
|
|
17
|
+
help="Manage event create rules",
|
|
18
|
+
no_args_is_help=True,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _load_json_config(config_file: str) -> dict:
|
|
23
|
+
"""Load and parse a JSON config file."""
|
|
24
|
+
config_path = Path(config_file)
|
|
25
|
+
if not config_path.exists():
|
|
26
|
+
raise typer.BadParameter(f"Config file not found: {config_file}")
|
|
27
|
+
try:
|
|
28
|
+
return json.loads(config_path.read_text())
|
|
29
|
+
except json.JSONDecodeError as exc:
|
|
30
|
+
raise typer.BadParameter(f"Invalid JSON in config file: {exc}")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@event_create_rules_app.command("list")
|
|
34
|
+
def list_cmd(
|
|
35
|
+
property_id: Optional[str] = typer.Option(
|
|
36
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
37
|
+
),
|
|
38
|
+
stream_id: str = typer.Option(
|
|
39
|
+
..., "--stream-id", "-s", help="Data stream ID"
|
|
40
|
+
),
|
|
41
|
+
output_format: Optional[str] = typer.Option(
|
|
42
|
+
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
43
|
+
),
|
|
44
|
+
):
|
|
45
|
+
"""List event create rules for a data stream."""
|
|
46
|
+
try:
|
|
47
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
48
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
49
|
+
effective_format = resolve_output_format(output_format)
|
|
50
|
+
|
|
51
|
+
admin = get_admin_alpha_client()
|
|
52
|
+
parent = f"properties/{effective_property}/dataStreams/{stream_id}"
|
|
53
|
+
rules = paginate_all(
|
|
54
|
+
lambda **kw: admin.properties()
|
|
55
|
+
.dataStreams()
|
|
56
|
+
.eventCreateRules()
|
|
57
|
+
.list(parent=parent, **kw)
|
|
58
|
+
.execute(),
|
|
59
|
+
"eventCreateRules",
|
|
60
|
+
pageSize=200,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
output(
|
|
64
|
+
rules,
|
|
65
|
+
effective_format,
|
|
66
|
+
columns=[
|
|
67
|
+
"name",
|
|
68
|
+
"destinationEvent",
|
|
69
|
+
"sourceCopyParameters",
|
|
70
|
+
],
|
|
71
|
+
headers=[
|
|
72
|
+
"Resource Name",
|
|
73
|
+
"Destination Event",
|
|
74
|
+
"Copy Source Params",
|
|
75
|
+
],
|
|
76
|
+
)
|
|
77
|
+
except Exception as e:
|
|
78
|
+
handle_error(e)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@event_create_rules_app.command("get")
|
|
82
|
+
def get_cmd(
|
|
83
|
+
property_id: Optional[str] = typer.Option(
|
|
84
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
85
|
+
),
|
|
86
|
+
stream_id: str = typer.Option(
|
|
87
|
+
..., "--stream-id", "-s", help="Data stream ID"
|
|
88
|
+
),
|
|
89
|
+
rule_id: str = typer.Option(
|
|
90
|
+
..., "--rule-id", "-r", help="Event create rule ID"
|
|
91
|
+
),
|
|
92
|
+
output_format: Optional[str] = typer.Option(
|
|
93
|
+
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
94
|
+
),
|
|
95
|
+
):
|
|
96
|
+
"""Get details for an event create rule."""
|
|
97
|
+
try:
|
|
98
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
99
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
100
|
+
effective_format = resolve_output_format(output_format)
|
|
101
|
+
|
|
102
|
+
admin = get_admin_alpha_client()
|
|
103
|
+
resource_name = (
|
|
104
|
+
f"properties/{effective_property}/dataStreams/{stream_id}"
|
|
105
|
+
f"/eventCreateRules/{rule_id}"
|
|
106
|
+
)
|
|
107
|
+
rule = (
|
|
108
|
+
admin.properties()
|
|
109
|
+
.dataStreams()
|
|
110
|
+
.eventCreateRules()
|
|
111
|
+
.get(name=resource_name)
|
|
112
|
+
.execute()
|
|
113
|
+
)
|
|
114
|
+
output(rule, effective_format)
|
|
115
|
+
except Exception as e:
|
|
116
|
+
handle_error(e)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@event_create_rules_app.command("create")
|
|
120
|
+
def create_cmd(
|
|
121
|
+
property_id: Optional[str] = typer.Option(
|
|
122
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
123
|
+
),
|
|
124
|
+
stream_id: str = typer.Option(
|
|
125
|
+
..., "--stream-id", "-s", help="Data stream ID"
|
|
126
|
+
),
|
|
127
|
+
config_file: str = typer.Option(
|
|
128
|
+
..., "--config", "-c", help="Path to JSON event create rule config file"
|
|
129
|
+
),
|
|
130
|
+
output_format: Optional[str] = typer.Option(
|
|
131
|
+
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
132
|
+
),
|
|
133
|
+
):
|
|
134
|
+
"""Create an event create rule from a JSON config file."""
|
|
135
|
+
try:
|
|
136
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
137
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
138
|
+
effective_format = resolve_output_format(output_format)
|
|
139
|
+
|
|
140
|
+
body = _load_json_config(config_file)
|
|
141
|
+
|
|
142
|
+
admin = get_admin_alpha_client()
|
|
143
|
+
parent = f"properties/{effective_property}/dataStreams/{stream_id}"
|
|
144
|
+
rule = (
|
|
145
|
+
admin.properties()
|
|
146
|
+
.dataStreams()
|
|
147
|
+
.eventCreateRules()
|
|
148
|
+
.create(parent=parent, body=body)
|
|
149
|
+
.execute()
|
|
150
|
+
)
|
|
151
|
+
output(rule, effective_format)
|
|
152
|
+
except typer.BadParameter:
|
|
153
|
+
raise
|
|
154
|
+
except Exception as e:
|
|
155
|
+
handle_error(e)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@event_create_rules_app.command("update")
|
|
159
|
+
def update_cmd(
|
|
160
|
+
property_id: Optional[str] = typer.Option(
|
|
161
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
162
|
+
),
|
|
163
|
+
stream_id: str = typer.Option(
|
|
164
|
+
..., "--stream-id", "-s", help="Data stream ID"
|
|
165
|
+
),
|
|
166
|
+
rule_id: str = typer.Option(
|
|
167
|
+
..., "--rule-id", "-r", help="Event create rule ID"
|
|
168
|
+
),
|
|
169
|
+
config_file: str = typer.Option(
|
|
170
|
+
..., "--config", "-c", help="Path to JSON file with fields to update"
|
|
171
|
+
),
|
|
172
|
+
output_format: Optional[str] = typer.Option(
|
|
173
|
+
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
174
|
+
),
|
|
175
|
+
):
|
|
176
|
+
"""Update an event create rule from a JSON config file."""
|
|
177
|
+
try:
|
|
178
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
179
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
180
|
+
effective_format = resolve_output_format(output_format)
|
|
181
|
+
|
|
182
|
+
body = _load_json_config(config_file)
|
|
183
|
+
|
|
184
|
+
if not body:
|
|
185
|
+
raise typer.BadParameter("Config file must contain at least one field to update.")
|
|
186
|
+
|
|
187
|
+
update_mask = ",".join(body.keys())
|
|
188
|
+
|
|
189
|
+
admin = get_admin_alpha_client()
|
|
190
|
+
resource_name = (
|
|
191
|
+
f"properties/{effective_property}/dataStreams/{stream_id}"
|
|
192
|
+
f"/eventCreateRules/{rule_id}"
|
|
193
|
+
)
|
|
194
|
+
rule = (
|
|
195
|
+
admin.properties()
|
|
196
|
+
.dataStreams()
|
|
197
|
+
.eventCreateRules()
|
|
198
|
+
.patch(
|
|
199
|
+
name=resource_name,
|
|
200
|
+
body=body,
|
|
201
|
+
updateMask=update_mask,
|
|
202
|
+
)
|
|
203
|
+
.execute()
|
|
204
|
+
)
|
|
205
|
+
output(rule, effective_format)
|
|
206
|
+
except typer.BadParameter:
|
|
207
|
+
raise
|
|
208
|
+
except Exception as e:
|
|
209
|
+
handle_error(e)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@event_create_rules_app.command("delete")
|
|
213
|
+
def delete_cmd(
|
|
214
|
+
property_id: Optional[str] = typer.Option(
|
|
215
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
216
|
+
),
|
|
217
|
+
stream_id: str = typer.Option(
|
|
218
|
+
..., "--stream-id", "-s", help="Data stream ID"
|
|
219
|
+
),
|
|
220
|
+
rule_id: str = typer.Option(
|
|
221
|
+
..., "--rule-id", "-r", help="Event create rule ID"
|
|
222
|
+
),
|
|
223
|
+
yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt"),
|
|
224
|
+
):
|
|
225
|
+
"""Delete an event create rule."""
|
|
226
|
+
try:
|
|
227
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
228
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
229
|
+
|
|
230
|
+
if not yes:
|
|
231
|
+
confirmed = questionary.confirm(
|
|
232
|
+
f"Delete event create rule {rule_id}? This cannot be undone."
|
|
233
|
+
).ask()
|
|
234
|
+
if not confirmed:
|
|
235
|
+
info("Cancelled.")
|
|
236
|
+
raise typer.Exit()
|
|
237
|
+
|
|
238
|
+
admin = get_admin_alpha_client()
|
|
239
|
+
resource_name = (
|
|
240
|
+
f"properties/{effective_property}/dataStreams/{stream_id}"
|
|
241
|
+
f"/eventCreateRules/{rule_id}"
|
|
242
|
+
)
|
|
243
|
+
admin.properties().dataStreams().eventCreateRules().delete(
|
|
244
|
+
name=resource_name
|
|
245
|
+
).execute()
|
|
246
|
+
success(f"Event create rule {rule_id} deleted.")
|
|
247
|
+
except typer.Exit:
|
|
248
|
+
raise
|
|
249
|
+
except Exception as e:
|
|
250
|
+
handle_error(e)
|