google-analytics-cli 0.1.3__tar.gz → 0.1.5__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.
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/PKG-INFO +5 -3
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/README.md +4 -2
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/pyproject.toml +1 -1
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/agent_cmd.py +8 -2
- google_analytics_cli-0.1.5/src/ga_cli/commands/enhanced_measurement.py +157 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/property_settings.py +1 -103
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/upgrade_cmd.py +11 -8
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/main.py +2 -0
- google_analytics_cli-0.1.5/tests/test_enhanced_measurement.py +179 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_property_settings.py +0 -171
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_upgrade_cmd.py +47 -4
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/uv.lock +1 -1
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/.api-snapshots/analyticsadmin_v1alpha.json +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/.api-snapshots/analyticsadmin_v1beta.json +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/.api-snapshots/analyticsdata_v1alpha.json +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/.api-snapshots/analyticsdata_v1beta.json +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/.github/workflows/api-watch.yml +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/.github/workflows/ci.yml +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/.github/workflows/release.yml +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/.gitignore +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/.python-version +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/install.sh +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/scripts/check_api_changes.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/__init__.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/api/__init__.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/api/client.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/auth/__init__.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/auth/credentials.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/auth/oauth.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/auth/service_account.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/__init__.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/access_bindings.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/access_reports.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/account_summaries.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/accounts.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/annotations.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/audiences.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/auth_cmd.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/bigquery_links.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/calculated_metrics.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/channel_groups.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/completions_cmd.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/config_cmd.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/custom_dimensions.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/custom_metrics.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/data_retention.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/data_streams.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/event_create_rules.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/event_edit_rules.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/firebase_links.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/google_ads_links.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/key_events.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/mp_secrets.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/properties.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/reports.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/config/__init__.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/config/constants.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/config/store.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/utils/__init__.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/utils/describe.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/utils/dry_run.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/utils/errors.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/utils/filters.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/utils/output.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/utils/pagination.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/__init__.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/conftest.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_access_bindings.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_access_reports.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_account_summaries.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_accounts.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_agent_cmd.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_annotations.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_api_client.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_api_diff.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_audiences.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_auth_cmd.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_bigquery_links.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_calculated_metrics.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_channel_groups.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_completions_cmd.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_config_cmd.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_credentials.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_custom_dimensions.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_custom_metrics.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_data_retention.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_data_streams.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_describe.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_dry_run.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_errors.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_event_create_rules.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_event_edit_rules.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_filters.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_firebase_links.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_google_ads_links.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_install_script.sh +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_key_events.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_mp_secrets.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_output.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_pagination.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_properties.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_quiet_nocolor.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_reports.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_reports_batch.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_reports_funnel.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_reports_pivot.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_service_account.py +0 -0
- {google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/tests/test_version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-analytics-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Command-line interface for Google Analytics 4
|
|
5
5
|
Project-URL: Homepage, https://github.com/daidalytics/google-analytics-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/daidalytics/google-analytics-cli
|
|
@@ -71,7 +71,8 @@ Manage GA4 accounts, properties, data streams, and run reports — all from your
|
|
|
71
71
|
- **Event create & edit rules** — Manage server-side event creation and modification rules
|
|
72
72
|
- **Firebase links** — List, create, and delete Firebase project links
|
|
73
73
|
- **Google Ads links** — List, create, update, and delete Google Ads account links
|
|
74
|
-
- **Property settings** — View and update attribution
|
|
74
|
+
- **Property settings** — View and update attribution and Google Signals settings
|
|
75
|
+
- **Enhanced measurement** — View and update enhanced measurement settings per data stream
|
|
75
76
|
|
|
76
77
|
### Interactive usage
|
|
77
78
|
|
|
@@ -229,7 +230,8 @@ export GA_CLI_SERVICE_ACCOUNT="/path/to/key.json"
|
|
|
229
230
|
| `ga event-edit-rules` | `list`, `get`, `create`, `update`, `delete`, `reorder` | Manage event editing rules |
|
|
230
231
|
| `ga firebase-links` | `list`, `create`, `delete` | Manage Firebase links |
|
|
231
232
|
| `ga google-ads-links` | `list`, `create`, `update`, `delete` | Manage Google Ads links |
|
|
232
|
-
| `ga
|
|
233
|
+
| `ga enhanced-measurement` | `get`, `update` | Manage enhanced measurement settings |
|
|
234
|
+
| `ga property-settings` | `attribution`, `google-signals` | View and update property settings |
|
|
233
235
|
| `ga reports` | `run`, `pivot`, `batch`, `funnel`, `check-compatibility`, `metadata`, `realtime`, `build` | Run and build reports |
|
|
234
236
|
| `ga agent` | `guide` | AI agent quick reference |
|
|
235
237
|
| `ga upgrade` | `--check`, `--force` | Check for and install updates |
|
|
@@ -38,7 +38,8 @@ Manage GA4 accounts, properties, data streams, and run reports — all from your
|
|
|
38
38
|
- **Event create & edit rules** — Manage server-side event creation and modification rules
|
|
39
39
|
- **Firebase links** — List, create, and delete Firebase project links
|
|
40
40
|
- **Google Ads links** — List, create, update, and delete Google Ads account links
|
|
41
|
-
- **Property settings** — View and update attribution
|
|
41
|
+
- **Property settings** — View and update attribution and Google Signals settings
|
|
42
|
+
- **Enhanced measurement** — View and update enhanced measurement settings per data stream
|
|
42
43
|
|
|
43
44
|
### Interactive usage
|
|
44
45
|
|
|
@@ -196,7 +197,8 @@ export GA_CLI_SERVICE_ACCOUNT="/path/to/key.json"
|
|
|
196
197
|
| `ga event-edit-rules` | `list`, `get`, `create`, `update`, `delete`, `reorder` | Manage event editing rules |
|
|
197
198
|
| `ga firebase-links` | `list`, `create`, `delete` | Manage Firebase links |
|
|
198
199
|
| `ga google-ads-links` | `list`, `create`, `update`, `delete` | Manage Google Ads links |
|
|
199
|
-
| `ga
|
|
200
|
+
| `ga enhanced-measurement` | `get`, `update` | Manage enhanced measurement settings |
|
|
201
|
+
| `ga property-settings` | `attribution`, `google-signals` | View and update property settings |
|
|
200
202
|
| `ga reports` | `run`, `pivot`, `batch`, `funnel`, `check-compatibility`, `metadata`, `realtime`, `build` | Run and build reports |
|
|
201
203
|
| `ga agent` | `guide` | AI agent quick reference |
|
|
202
204
|
| `ga upgrade` | `--check`, `--force` | Check for and install updates |
|
|
@@ -231,9 +231,15 @@ Requires both `--property-id` and `--stream-id`. Create/update use `--config` JS
|
|
|
231
231
|
```bash
|
|
232
232
|
ga property-settings attribution [-p PROPERTY_ID] [--attribution-model MODEL] [--acquisition-lookback VAL] [--other-lookback VAL] [--ads-export-scope VAL] [-o json]
|
|
233
233
|
ga property-settings google-signals [-p PROPERTY_ID] [--state GOOGLE_SIGNALS_ENABLED|GOOGLE_SIGNALS_DISABLED] [-o json]
|
|
234
|
-
ga property-settings enhanced-measurement [-p PROPERTY_ID] -s STREAM_ID [--scrolls/--no-scrolls] [--outbound-clicks/--no-outbound-clicks] [...] [-o json]
|
|
235
234
|
```
|
|
236
|
-
Get/set hybrid: no update flags = GET, any update flag = PATCH.
|
|
235
|
+
Get/set hybrid: no update flags = GET, any update flag = PATCH.
|
|
236
|
+
|
|
237
|
+
### Enhanced Measurement Settings (alpha)
|
|
238
|
+
```bash
|
|
239
|
+
ga enhanced-measurement get -p PROPERTY_ID -s STREAM_ID [-o json]
|
|
240
|
+
ga enhanced-measurement update -p PROPERTY_ID -s STREAM_ID [--scrolls/--no-scrolls] [--outbound-clicks/--no-outbound-clicks] [--site-search/--no-site-search] [--video-engagement/--no-video-engagement] [--file-downloads/--no-file-downloads] [--page-changes/--no-page-changes] [--form-interactions/--no-form-interactions] [--stream-enabled/--no-stream-enabled] [--search-query-parameter VAL] [--uri-query-parameter VAL] [--dry-run] [-o json]
|
|
241
|
+
```
|
|
242
|
+
Requires both `--property-id` and `--stream-id`. `get` retrieves current settings; `update` requires at least one toggle flag.
|
|
237
243
|
|
|
238
244
|
### Reports
|
|
239
245
|
```bash
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""Enhanced measurement settings commands for a data stream."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from ..api.client import get_admin_alpha_client
|
|
8
|
+
from ..config.store import get_effective_value
|
|
9
|
+
from ..utils import (
|
|
10
|
+
handle_dry_run,
|
|
11
|
+
handle_error,
|
|
12
|
+
output,
|
|
13
|
+
require_options,
|
|
14
|
+
resolve_output_format,
|
|
15
|
+
success,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
enhanced_measurement_app = typer.Typer(
|
|
19
|
+
name="enhanced-measurement",
|
|
20
|
+
help="Manage enhanced measurement settings for a data stream",
|
|
21
|
+
no_args_is_help=True,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _resource_name(property_id: str, stream_id: str) -> str:
|
|
26
|
+
return (
|
|
27
|
+
f"properties/{property_id}/dataStreams/{stream_id}"
|
|
28
|
+
"/enhancedMeasurementSettings"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@enhanced_measurement_app.command("get")
|
|
33
|
+
def get_cmd(
|
|
34
|
+
property_id: Optional[str] = typer.Option(
|
|
35
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
36
|
+
),
|
|
37
|
+
stream_id: str = typer.Option(
|
|
38
|
+
..., "--stream-id", "-s", help="Data stream ID"
|
|
39
|
+
),
|
|
40
|
+
output_format: Optional[str] = typer.Option(
|
|
41
|
+
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
42
|
+
),
|
|
43
|
+
):
|
|
44
|
+
"""Get enhanced measurement settings for a data stream."""
|
|
45
|
+
try:
|
|
46
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
47
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
48
|
+
effective_format = resolve_output_format(output_format)
|
|
49
|
+
|
|
50
|
+
admin = get_admin_alpha_client()
|
|
51
|
+
settings = (
|
|
52
|
+
admin.properties()
|
|
53
|
+
.dataStreams()
|
|
54
|
+
.getEnhancedMeasurementSettings(
|
|
55
|
+
name=_resource_name(effective_property, stream_id)
|
|
56
|
+
)
|
|
57
|
+
.execute()
|
|
58
|
+
)
|
|
59
|
+
output(settings, effective_format)
|
|
60
|
+
except Exception as e:
|
|
61
|
+
handle_error(e)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@enhanced_measurement_app.command("update")
|
|
65
|
+
def update_cmd(
|
|
66
|
+
property_id: Optional[str] = typer.Option(
|
|
67
|
+
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
68
|
+
),
|
|
69
|
+
stream_id: str = typer.Option(
|
|
70
|
+
..., "--stream-id", "-s", help="Data stream ID"
|
|
71
|
+
),
|
|
72
|
+
stream_enabled: Optional[bool] = typer.Option(
|
|
73
|
+
None,
|
|
74
|
+
"--stream-enabled/--no-stream-enabled",
|
|
75
|
+
help="Enable/disable enhanced measurement for this stream",
|
|
76
|
+
),
|
|
77
|
+
scrolls: Optional[bool] = typer.Option(
|
|
78
|
+
None, "--scrolls/--no-scrolls", help="Capture scroll events"
|
|
79
|
+
),
|
|
80
|
+
outbound_clicks: Optional[bool] = typer.Option(
|
|
81
|
+
None, "--outbound-clicks/--no-outbound-clicks", help="Capture outbound click events"
|
|
82
|
+
),
|
|
83
|
+
site_search: Optional[bool] = typer.Option(
|
|
84
|
+
None, "--site-search/--no-site-search", help="Capture site search events"
|
|
85
|
+
),
|
|
86
|
+
video_engagement: Optional[bool] = typer.Option(
|
|
87
|
+
None, "--video-engagement/--no-video-engagement", help="Capture video engagement events"
|
|
88
|
+
),
|
|
89
|
+
file_downloads: Optional[bool] = typer.Option(
|
|
90
|
+
None, "--file-downloads/--no-file-downloads", help="Capture file download events"
|
|
91
|
+
),
|
|
92
|
+
page_changes: Optional[bool] = typer.Option(
|
|
93
|
+
None, "--page-changes/--no-page-changes", help="Capture page change (history) events"
|
|
94
|
+
),
|
|
95
|
+
form_interactions: Optional[bool] = typer.Option(
|
|
96
|
+
None, "--form-interactions/--no-form-interactions", help="Capture form interaction events"
|
|
97
|
+
),
|
|
98
|
+
search_query_parameter: Optional[str] = typer.Option(
|
|
99
|
+
None, "--search-query-parameter", help="URL query parameters for site search"
|
|
100
|
+
),
|
|
101
|
+
uri_query_parameter: Optional[str] = typer.Option(
|
|
102
|
+
None, "--uri-query-parameter", help="Additional URL query parameters"
|
|
103
|
+
),
|
|
104
|
+
dry_run: bool = typer.Option(
|
|
105
|
+
False, "--dry-run", help="Preview the request without executing"
|
|
106
|
+
),
|
|
107
|
+
output_format: Optional[str] = typer.Option(
|
|
108
|
+
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
109
|
+
),
|
|
110
|
+
):
|
|
111
|
+
"""Update enhanced measurement settings for a data stream."""
|
|
112
|
+
try:
|
|
113
|
+
effective_property = get_effective_value(property_id, "default_property_id")
|
|
114
|
+
require_options({"property_id": effective_property}, ["property_id"])
|
|
115
|
+
effective_format = resolve_output_format(output_format)
|
|
116
|
+
|
|
117
|
+
field_map = {
|
|
118
|
+
"streamEnabled": stream_enabled,
|
|
119
|
+
"scrollsEnabled": scrolls,
|
|
120
|
+
"outboundClicksEnabled": outbound_clicks,
|
|
121
|
+
"siteSearchEnabled": site_search,
|
|
122
|
+
"videoEngagementEnabled": video_engagement,
|
|
123
|
+
"fileDownloadsEnabled": file_downloads,
|
|
124
|
+
"pageChangesEnabled": page_changes,
|
|
125
|
+
"formInteractionsEnabled": form_interactions,
|
|
126
|
+
"searchQueryParameter": search_query_parameter,
|
|
127
|
+
"uriQueryParameter": uri_query_parameter,
|
|
128
|
+
}
|
|
129
|
+
body = {k: v for k, v in field_map.items() if v is not None}
|
|
130
|
+
|
|
131
|
+
if not body:
|
|
132
|
+
raise typer.BadParameter(
|
|
133
|
+
"At least one update flag must be specified (e.g. --scrolls, "
|
|
134
|
+
"--stream-enabled, --search-query-parameter)."
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
update_mask = ",".join(body.keys())
|
|
138
|
+
resource = _resource_name(effective_property, stream_id)
|
|
139
|
+
|
|
140
|
+
if dry_run:
|
|
141
|
+
handle_dry_run("update", "PATCH", resource, body, update_mask=update_mask)
|
|
142
|
+
|
|
143
|
+
admin = get_admin_alpha_client()
|
|
144
|
+
settings = (
|
|
145
|
+
admin.properties()
|
|
146
|
+
.dataStreams()
|
|
147
|
+
.updateEnhancedMeasurementSettings(
|
|
148
|
+
name=resource, updateMask=update_mask, body=body
|
|
149
|
+
)
|
|
150
|
+
.execute()
|
|
151
|
+
)
|
|
152
|
+
success("Enhanced measurement settings updated.")
|
|
153
|
+
output(settings, effective_format)
|
|
154
|
+
except (typer.BadParameter, typer.Exit):
|
|
155
|
+
raise
|
|
156
|
+
except Exception as e:
|
|
157
|
+
handle_error(e)
|
{google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/property_settings.py
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Property settings commands (attribution, Google Signals
|
|
1
|
+
"""Property settings commands (attribution, Google Signals)."""
|
|
2
2
|
|
|
3
3
|
from typing import Optional
|
|
4
4
|
|
|
@@ -183,105 +183,3 @@ def google_signals_cmd(
|
|
|
183
183
|
raise
|
|
184
184
|
except Exception as e:
|
|
185
185
|
handle_error(e)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
# --- Enhanced Measurement Settings ---
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
@property_settings_app.command("enhanced-measurement")
|
|
192
|
-
def enhanced_measurement_cmd(
|
|
193
|
-
property_id: Optional[str] = typer.Option(
|
|
194
|
-
None, "--property-id", "-p", help="Property ID (numeric)"
|
|
195
|
-
),
|
|
196
|
-
stream_id: str = typer.Option(
|
|
197
|
-
..., "--stream-id", "-s", help="Data stream ID"
|
|
198
|
-
),
|
|
199
|
-
stream_enabled: Optional[bool] = typer.Option(
|
|
200
|
-
None,
|
|
201
|
-
"--stream-enabled/--no-stream-enabled",
|
|
202
|
-
help="Enable/disable enhanced measurement for this stream",
|
|
203
|
-
),
|
|
204
|
-
scrolls: Optional[bool] = typer.Option(
|
|
205
|
-
None, "--scrolls/--no-scrolls", help="Capture scroll events"
|
|
206
|
-
),
|
|
207
|
-
outbound_clicks: Optional[bool] = typer.Option(
|
|
208
|
-
None, "--outbound-clicks/--no-outbound-clicks", help="Capture outbound click events"
|
|
209
|
-
),
|
|
210
|
-
site_search: Optional[bool] = typer.Option(
|
|
211
|
-
None, "--site-search/--no-site-search", help="Capture site search events"
|
|
212
|
-
),
|
|
213
|
-
video_engagement: Optional[bool] = typer.Option(
|
|
214
|
-
None, "--video-engagement/--no-video-engagement", help="Capture video engagement events"
|
|
215
|
-
),
|
|
216
|
-
file_downloads: Optional[bool] = typer.Option(
|
|
217
|
-
None, "--file-downloads/--no-file-downloads", help="Capture file download events"
|
|
218
|
-
),
|
|
219
|
-
page_changes: Optional[bool] = typer.Option(
|
|
220
|
-
None, "--page-changes/--no-page-changes", help="Capture page change (history) events"
|
|
221
|
-
),
|
|
222
|
-
form_interactions: Optional[bool] = typer.Option(
|
|
223
|
-
None, "--form-interactions/--no-form-interactions", help="Capture form interaction events"
|
|
224
|
-
),
|
|
225
|
-
search_query_parameter: Optional[str] = typer.Option(
|
|
226
|
-
None, "--search-query-parameter", help="URL query parameters for site search"
|
|
227
|
-
),
|
|
228
|
-
uri_query_parameter: Optional[str] = typer.Option(
|
|
229
|
-
None, "--uri-query-parameter", help="Additional URL query parameters"
|
|
230
|
-
),
|
|
231
|
-
output_format: Optional[str] = typer.Option(
|
|
232
|
-
None, "--output", "-o", help="Output format (json, table, compact)"
|
|
233
|
-
),
|
|
234
|
-
):
|
|
235
|
-
"""Get or update enhanced measurement settings.
|
|
236
|
-
|
|
237
|
-
With no update flags, displays current settings.
|
|
238
|
-
"""
|
|
239
|
-
try:
|
|
240
|
-
effective_property = get_effective_value(property_id, "default_property_id")
|
|
241
|
-
require_options({"property_id": effective_property}, ["property_id"])
|
|
242
|
-
effective_format = resolve_output_format(output_format)
|
|
243
|
-
|
|
244
|
-
resource_name = (
|
|
245
|
-
f"properties/{effective_property}/dataStreams/{stream_id}"
|
|
246
|
-
"/enhancedMeasurementSettings"
|
|
247
|
-
)
|
|
248
|
-
admin = get_admin_alpha_client()
|
|
249
|
-
|
|
250
|
-
field_map = {
|
|
251
|
-
"streamEnabled": stream_enabled,
|
|
252
|
-
"scrollsEnabled": scrolls,
|
|
253
|
-
"outboundClicksEnabled": outbound_clicks,
|
|
254
|
-
"siteSearchEnabled": site_search,
|
|
255
|
-
"videoEngagementEnabled": video_engagement,
|
|
256
|
-
"fileDownloadsEnabled": file_downloads,
|
|
257
|
-
"pageChangesEnabled": page_changes,
|
|
258
|
-
"formInteractionsEnabled": form_interactions,
|
|
259
|
-
"searchQueryParameter": search_query_parameter,
|
|
260
|
-
"uriQueryParameter": uri_query_parameter,
|
|
261
|
-
}
|
|
262
|
-
body = {k: v for k, v in field_map.items() if v is not None}
|
|
263
|
-
|
|
264
|
-
if body:
|
|
265
|
-
update_mask = ",".join(body.keys())
|
|
266
|
-
settings = (
|
|
267
|
-
admin.properties()
|
|
268
|
-
.dataStreams()
|
|
269
|
-
.updateEnhancedMeasurementSettings(
|
|
270
|
-
name=resource_name, updateMask=update_mask, body=body
|
|
271
|
-
)
|
|
272
|
-
.execute()
|
|
273
|
-
)
|
|
274
|
-
success("Enhanced measurement settings updated.")
|
|
275
|
-
else:
|
|
276
|
-
settings = (
|
|
277
|
-
admin.properties()
|
|
278
|
-
.dataStreams()
|
|
279
|
-
.getEnhancedMeasurementSettings(name=resource_name)
|
|
280
|
-
.execute()
|
|
281
|
-
)
|
|
282
|
-
|
|
283
|
-
output(settings, effective_format)
|
|
284
|
-
except typer.BadParameter:
|
|
285
|
-
raise
|
|
286
|
-
except Exception as e:
|
|
287
|
-
handle_error(e)
|
{google_analytics_cli-0.1.3 → google_analytics_cli-0.1.5}/src/ga_cli/commands/upgrade_cmd.py
RENAMED
|
@@ -20,7 +20,7 @@ upgrade_app = typer.Typer(
|
|
|
20
20
|
name="upgrade", help="Check for and install updates", invoke_without_command=True
|
|
21
21
|
)
|
|
22
22
|
|
|
23
|
-
PYPI_URL = "https://pypi.org/pypi/
|
|
23
|
+
PYPI_URL = "https://pypi.org/pypi/google-analytics-cli/json"
|
|
24
24
|
PYPI_TIMEOUT = 5
|
|
25
25
|
UPDATE_CHECK_INTERVAL = 86400 # 24 hours in seconds
|
|
26
26
|
|
|
@@ -49,11 +49,13 @@ def _is_newer(latest: str, current: str) -> bool:
|
|
|
49
49
|
def _detect_installer() -> list[str]:
|
|
50
50
|
"""Detect the best install command to upgrade ga-cli.
|
|
51
51
|
|
|
52
|
-
Checks for
|
|
52
|
+
Checks for uv first, then pipx, then falls back to pip.
|
|
53
53
|
"""
|
|
54
|
+
if shutil.which("uv"):
|
|
55
|
+
return ["uv", "pip", "install", "--upgrade", "google-analytics-cli"]
|
|
54
56
|
if shutil.which("pipx"):
|
|
55
|
-
return ["pipx", "upgrade", "
|
|
56
|
-
return [sys.executable, "-m", "pip", "install", "--upgrade", "
|
|
57
|
+
return ["pipx", "upgrade", "google-analytics-cli"]
|
|
58
|
+
return [sys.executable, "-m", "pip", "install", "--upgrade", "google-analytics-cli"]
|
|
57
59
|
|
|
58
60
|
|
|
59
61
|
@upgrade_app.callback(invoke_without_command=True)
|
|
@@ -78,11 +80,12 @@ def upgrade_cmd(
|
|
|
78
80
|
if force:
|
|
79
81
|
info(f"Force-reinstalling ga-cli {current}...")
|
|
80
82
|
cmd = _detect_installer()
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
if cmd[0] == "pipx":
|
|
84
|
+
cmd = ["pipx", "install", "--force", "google-analytics-cli"]
|
|
85
|
+
elif cmd[0] == "uv":
|
|
86
|
+
cmd.append("--reinstall")
|
|
84
87
|
else:
|
|
85
|
-
cmd
|
|
88
|
+
cmd.append("--force-reinstall")
|
|
86
89
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
87
90
|
if result.returncode == 0:
|
|
88
91
|
success(f"Reinstalled ga-cli {current}.")
|
|
@@ -19,6 +19,7 @@ from .commands.custom_dimensions import custom_dimensions_app
|
|
|
19
19
|
from .commands.custom_metrics import custom_metrics_app
|
|
20
20
|
from .commands.data_retention import data_retention_app
|
|
21
21
|
from .commands.data_streams import data_streams_app
|
|
22
|
+
from .commands.enhanced_measurement import enhanced_measurement_app
|
|
22
23
|
from .commands.event_create_rules import event_create_rules_app
|
|
23
24
|
from .commands.event_edit_rules import event_edit_rules_app
|
|
24
25
|
from .commands.firebase_links import firebase_links_app
|
|
@@ -53,6 +54,7 @@ app.add_typer(audiences_app, name="audiences")
|
|
|
53
54
|
app.add_typer(bigquery_links_app, name="bigquery-links")
|
|
54
55
|
app.add_typer(calculated_metrics_app, name="calculated-metrics")
|
|
55
56
|
app.add_typer(channel_groups_app, name="channel-groups")
|
|
57
|
+
app.add_typer(enhanced_measurement_app, name="enhanced-measurement")
|
|
56
58
|
app.add_typer(event_create_rules_app, name="event-create-rules")
|
|
57
59
|
app.add_typer(event_edit_rules_app, name="event-edit-rules")
|
|
58
60
|
app.add_typer(firebase_links_app, name="firebase-links")
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Tests for enhanced measurement settings commands."""
|
|
2
|
+
|
|
3
|
+
from unittest.mock import MagicMock, patch
|
|
4
|
+
|
|
5
|
+
from typer.testing import CliRunner
|
|
6
|
+
|
|
7
|
+
from ga_cli.config.store import UserConfig, save_config
|
|
8
|
+
from ga_cli.main import app
|
|
9
|
+
|
|
10
|
+
runner = CliRunner()
|
|
11
|
+
|
|
12
|
+
SAMPLE_ENHANCED = {
|
|
13
|
+
"name": "properties/123/dataStreams/456/enhancedMeasurementSettings",
|
|
14
|
+
"streamEnabled": True,
|
|
15
|
+
"scrollsEnabled": True,
|
|
16
|
+
"outboundClicksEnabled": True,
|
|
17
|
+
"siteSearchEnabled": True,
|
|
18
|
+
"videoEngagementEnabled": True,
|
|
19
|
+
"fileDownloadsEnabled": True,
|
|
20
|
+
"pageChangesEnabled": True,
|
|
21
|
+
"formInteractionsEnabled": False,
|
|
22
|
+
"searchQueryParameter": "q,s,search",
|
|
23
|
+
"uriQueryParameter": "",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
_PATCH_TARGET = "ga_cli.commands.enhanced_measurement.get_admin_alpha_client"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _mock_admin_alpha_client():
|
|
30
|
+
"""Create a mock Admin API alpha client with enhanced measurement methods."""
|
|
31
|
+
mock_client = MagicMock()
|
|
32
|
+
ds = mock_client.properties.return_value.dataStreams.return_value
|
|
33
|
+
ds.getEnhancedMeasurementSettings.return_value.execute.return_value = SAMPLE_ENHANCED
|
|
34
|
+
ds.updateEnhancedMeasurementSettings.return_value.execute.return_value = SAMPLE_ENHANCED
|
|
35
|
+
return mock_client
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TestEnhancedMeasurementGet:
|
|
39
|
+
def test_get(self):
|
|
40
|
+
mock_client = _mock_admin_alpha_client()
|
|
41
|
+
|
|
42
|
+
with patch(_PATCH_TARGET, return_value=mock_client):
|
|
43
|
+
result = runner.invoke(
|
|
44
|
+
app,
|
|
45
|
+
["enhanced-measurement", "get", "-p", "123", "-s", "456"],
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
assert result.exit_code == 0
|
|
49
|
+
ds = mock_client.properties.return_value.dataStreams.return_value
|
|
50
|
+
ds.getEnhancedMeasurementSettings.assert_called_once()
|
|
51
|
+
|
|
52
|
+
def test_get_json(self):
|
|
53
|
+
mock_client = _mock_admin_alpha_client()
|
|
54
|
+
|
|
55
|
+
with patch(_PATCH_TARGET, return_value=mock_client):
|
|
56
|
+
result = runner.invoke(
|
|
57
|
+
app,
|
|
58
|
+
[
|
|
59
|
+
"enhanced-measurement", "get",
|
|
60
|
+
"-p", "123", "-s", "456", "-o", "json",
|
|
61
|
+
],
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
assert result.exit_code == 0
|
|
65
|
+
assert '"scrollsEnabled"' in result.output
|
|
66
|
+
|
|
67
|
+
def test_get_uses_config_default(self):
|
|
68
|
+
save_config(UserConfig(default_property_id="123"))
|
|
69
|
+
mock_client = _mock_admin_alpha_client()
|
|
70
|
+
|
|
71
|
+
with patch(_PATCH_TARGET, return_value=mock_client):
|
|
72
|
+
result = runner.invoke(
|
|
73
|
+
app,
|
|
74
|
+
["enhanced-measurement", "get", "-s", "456"],
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
assert result.exit_code == 0
|
|
78
|
+
|
|
79
|
+
def test_missing_stream_id(self):
|
|
80
|
+
result = runner.invoke(
|
|
81
|
+
app,
|
|
82
|
+
["enhanced-measurement", "get", "-p", "123"],
|
|
83
|
+
)
|
|
84
|
+
assert result.exit_code != 0
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class TestEnhancedMeasurementUpdate:
|
|
88
|
+
def test_update_single_boolean(self):
|
|
89
|
+
mock_client = _mock_admin_alpha_client()
|
|
90
|
+
|
|
91
|
+
with patch(_PATCH_TARGET, return_value=mock_client):
|
|
92
|
+
result = runner.invoke(
|
|
93
|
+
app,
|
|
94
|
+
[
|
|
95
|
+
"enhanced-measurement", "update",
|
|
96
|
+
"-p", "123", "-s", "456",
|
|
97
|
+
"--no-scrolls",
|
|
98
|
+
],
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
assert result.exit_code == 0
|
|
102
|
+
assert "updated" in result.output.lower()
|
|
103
|
+
ds = mock_client.properties.return_value.dataStreams.return_value
|
|
104
|
+
call_args = ds.updateEnhancedMeasurementSettings.call_args[1]
|
|
105
|
+
assert call_args["body"]["scrollsEnabled"] is False
|
|
106
|
+
assert "scrollsEnabled" in call_args["updateMask"]
|
|
107
|
+
|
|
108
|
+
def test_update_multiple_booleans(self):
|
|
109
|
+
mock_client = _mock_admin_alpha_client()
|
|
110
|
+
|
|
111
|
+
with patch(_PATCH_TARGET, return_value=mock_client):
|
|
112
|
+
result = runner.invoke(
|
|
113
|
+
app,
|
|
114
|
+
[
|
|
115
|
+
"enhanced-measurement", "update",
|
|
116
|
+
"-p", "123", "-s", "456",
|
|
117
|
+
"--form-interactions",
|
|
118
|
+
"--no-video-engagement",
|
|
119
|
+
],
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
assert result.exit_code == 0
|
|
123
|
+
ds = mock_client.properties.return_value.dataStreams.return_value
|
|
124
|
+
call_args = ds.updateEnhancedMeasurementSettings.call_args[1]
|
|
125
|
+
assert call_args["body"]["formInteractionsEnabled"] is True
|
|
126
|
+
assert call_args["body"]["videoEngagementEnabled"] is False
|
|
127
|
+
|
|
128
|
+
def test_update_search_query_parameter(self):
|
|
129
|
+
mock_client = _mock_admin_alpha_client()
|
|
130
|
+
|
|
131
|
+
with patch(_PATCH_TARGET, return_value=mock_client):
|
|
132
|
+
result = runner.invoke(
|
|
133
|
+
app,
|
|
134
|
+
[
|
|
135
|
+
"enhanced-measurement", "update",
|
|
136
|
+
"-p", "123", "-s", "456",
|
|
137
|
+
"--search-query-parameter", "q,search,query",
|
|
138
|
+
],
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
assert result.exit_code == 0
|
|
142
|
+
ds = mock_client.properties.return_value.dataStreams.return_value
|
|
143
|
+
call_args = ds.updateEnhancedMeasurementSettings.call_args[1]
|
|
144
|
+
assert call_args["body"]["searchQueryParameter"] == "q,search,query"
|
|
145
|
+
|
|
146
|
+
def test_update_no_flags_errors(self):
|
|
147
|
+
result = runner.invoke(
|
|
148
|
+
app,
|
|
149
|
+
["enhanced-measurement", "update", "-p", "123", "-s", "456"],
|
|
150
|
+
)
|
|
151
|
+
assert result.exit_code != 0
|
|
152
|
+
|
|
153
|
+
def test_update_api_error(self):
|
|
154
|
+
from googleapiclient.errors import HttpError
|
|
155
|
+
|
|
156
|
+
mock_client = _mock_admin_alpha_client()
|
|
157
|
+
ds = mock_client.properties.return_value.dataStreams.return_value
|
|
158
|
+
ds.updateEnhancedMeasurementSettings.return_value.execute.side_effect = HttpError(
|
|
159
|
+
resp=MagicMock(status=400), content=b'{"error": {"message": "Bad request"}}'
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
with patch(_PATCH_TARGET, return_value=mock_client):
|
|
163
|
+
result = runner.invoke(
|
|
164
|
+
app,
|
|
165
|
+
[
|
|
166
|
+
"enhanced-measurement", "update",
|
|
167
|
+
"-p", "123", "-s", "456",
|
|
168
|
+
"--no-scrolls",
|
|
169
|
+
],
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
assert result.exit_code == 3
|
|
173
|
+
|
|
174
|
+
def test_missing_stream_id(self):
|
|
175
|
+
result = runner.invoke(
|
|
176
|
+
app,
|
|
177
|
+
["enhanced-measurement", "update", "-p", "123", "--no-scrolls"],
|
|
178
|
+
)
|
|
179
|
+
assert result.exit_code != 0
|