ga4-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.
- ga4_cli-0.1.0.dist-info/METADATA +253 -0
- ga4_cli-0.1.0.dist-info/RECORD +32 -0
- ga4_cli-0.1.0.dist-info/WHEEL +5 -0
- ga4_cli-0.1.0.dist-info/entry_points.txt +2 -0
- ga4_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- ga4_cli-0.1.0.dist-info/top_level.txt +2 -0
- ga_cli/__init__.py +3 -0
- ga_cli/auth.py +59 -0
- ga_cli/cli.py +35 -0
- ga_cli/commands/__init__.py +0 -0
- ga_cli/commands/accounts.py +81 -0
- ga_cli/commands/config.py +65 -0
- ga_cli/commands/datastreams.py +146 -0
- ga_cli/commands/properties.py +151 -0
- ga_cli/config.py +95 -0
- ga_cli/decorators.py +90 -0
- ga_cli/errors.py +35 -0
- ga_cli/formatters/__init__.py +0 -0
- ga_cli/formatters/json.py +9 -0
- ga_cli/formatters/table.py +23 -0
- ga_cli/logging_config.py +44 -0
- ga_cli/output.py +59 -0
- ga_cli/retry.py +40 -0
- ga_cli/validators.py +52 -0
- tests/__init__.py +0 -0
- tests/conftest.py +89 -0
- tests/test_accounts.py +49 -0
- tests/test_auth.py +74 -0
- tests/test_cli.py +52 -0
- tests/test_config.py +140 -0
- tests/test_errors.py +73 -0
- tests/test_validators.py +146 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ga4-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Command-line interface for Google Analytics 4
|
|
5
|
+
Home-page: https://github.com/sulimanbenhalim/ga-cli
|
|
6
|
+
Author: Suliman Ben Halim
|
|
7
|
+
Author-email: suliman.benhalim@binary.ly
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Bug Reports, https://github.com/sulimanbenhalim/ga-cli/issues
|
|
10
|
+
Project-URL: Source, https://github.com/sulimanbenhalim/ga-cli
|
|
11
|
+
Project-URL: Documentation, https://github.com/sulimanbenhalim/ga-cli#readme
|
|
12
|
+
Keywords: google-analytics ga4 cli command-line
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Requires-Python: >=3.8
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: click<9.0.0,>=8.0.0
|
|
26
|
+
Requires-Dist: google-analytics-admin<1.0.0,>=0.27.0
|
|
27
|
+
Requires-Dist: google-auth<3.0.0,>=2.0.0
|
|
28
|
+
Requires-Dist: rich<14.0.0,>=13.0.0
|
|
29
|
+
Requires-Dist: pytz>=2023.3
|
|
30
|
+
Dynamic: author
|
|
31
|
+
Dynamic: author-email
|
|
32
|
+
Dynamic: classifier
|
|
33
|
+
Dynamic: description
|
|
34
|
+
Dynamic: description-content-type
|
|
35
|
+
Dynamic: home-page
|
|
36
|
+
Dynamic: keywords
|
|
37
|
+
Dynamic: license
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
Dynamic: project-url
|
|
40
|
+
Dynamic: requires-dist
|
|
41
|
+
Dynamic: requires-python
|
|
42
|
+
Dynamic: summary
|
|
43
|
+
|
|
44
|
+
# GA CLI - Google Analytics Command Line Interface
|
|
45
|
+
|
|
46
|
+
A command-line interface tool for managing Google Analytics 4 properties, accounts, and data streams.
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
- List and manage Google Analytics accounts
|
|
51
|
+
- Create and manage GA4 properties
|
|
52
|
+
- Manage data streams and retrieve measurement IDs
|
|
53
|
+
- Beautiful table output with Rich
|
|
54
|
+
- JSON output support
|
|
55
|
+
- Authentication via service account credentials
|
|
56
|
+
|
|
57
|
+
## Installation
|
|
58
|
+
|
|
59
|
+
### From source
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
cd ga-cli
|
|
63
|
+
pip install -e .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Using pip (when published)
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install ga-cli
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Setup
|
|
73
|
+
|
|
74
|
+
### 1. Get Google Service Account Credentials
|
|
75
|
+
|
|
76
|
+
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
|
77
|
+
2. Create or select a project
|
|
78
|
+
3. Enable the Google Analytics Admin API
|
|
79
|
+
4. Create a service account with Analytics Admin permissions
|
|
80
|
+
5. Download the JSON credentials file
|
|
81
|
+
|
|
82
|
+
### 2. Initialize GA CLI
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
ga-cli config init
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
This will prompt you for the path to your service account JSON file and test the credentials.
|
|
89
|
+
|
|
90
|
+
Alternatively, set the environment variable:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/credentials.json
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Usage
|
|
97
|
+
|
|
98
|
+
### Configuration
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Initialize with credentials
|
|
102
|
+
ga-cli config init
|
|
103
|
+
|
|
104
|
+
# Show current configuration
|
|
105
|
+
ga-cli config show
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Accounts
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
# List all accounts
|
|
112
|
+
ga-cli accounts list
|
|
113
|
+
|
|
114
|
+
# Get account details
|
|
115
|
+
ga-cli accounts get <account-id>
|
|
116
|
+
|
|
117
|
+
# Output as JSON
|
|
118
|
+
ga-cli accounts list --format json
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Properties
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
# List properties for an account
|
|
125
|
+
ga-cli properties list <account-id>
|
|
126
|
+
|
|
127
|
+
# Get property details
|
|
128
|
+
ga-cli properties get <property-id>
|
|
129
|
+
|
|
130
|
+
# Create a new property
|
|
131
|
+
ga-cli properties create <account-id> --name "My Website" --timezone "America/New_York" --currency "USD"
|
|
132
|
+
|
|
133
|
+
# Delete a property
|
|
134
|
+
ga-cli properties delete <property-id>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Data Streams
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# List data streams for a property
|
|
141
|
+
ga-cli datastreams list <property-id>
|
|
142
|
+
|
|
143
|
+
# Get data stream details (including measurement ID)
|
|
144
|
+
ga-cli datastreams get <property-id> <stream-id>
|
|
145
|
+
|
|
146
|
+
# Create a new web data stream
|
|
147
|
+
ga-cli datastreams create <property-id> --name "Main Website" --url "https://example.com"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Examples
|
|
151
|
+
|
|
152
|
+
### Quick workflow to create a new GA4 property
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# 1. List your accounts to get the account ID
|
|
156
|
+
ga-cli accounts list
|
|
157
|
+
|
|
158
|
+
# 2. Create a new property
|
|
159
|
+
ga-cli properties create 123456789 --name "BOTCHA" --timezone "Africa/Tripoli"
|
|
160
|
+
|
|
161
|
+
# 3. Create a web data stream
|
|
162
|
+
ga-cli datastreams create 987654321 --name "BOTCHA Website" --url "https://botcha.example.com"
|
|
163
|
+
|
|
164
|
+
# 4. Get the measurement ID
|
|
165
|
+
ga-cli datastreams get 987654321 111222333
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Get measurement ID quickly
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# If you know your property and stream IDs
|
|
172
|
+
ga-cli datastreams get <property-id> <stream-id> | grep "Measurement ID"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Command Reference
|
|
176
|
+
|
|
177
|
+
### Global Options
|
|
178
|
+
|
|
179
|
+
- `--credentials PATH` - Path to service account credentials file
|
|
180
|
+
- `--version` - Show version
|
|
181
|
+
- `--help` - Show help message
|
|
182
|
+
|
|
183
|
+
### Output Formats
|
|
184
|
+
|
|
185
|
+
Most list and get commands support:
|
|
186
|
+
- `--format table` (default) - Beautiful table output
|
|
187
|
+
- `--format json` - JSON output
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
### Setup development environment
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
# Clone the repository
|
|
195
|
+
git clone <repository-url>
|
|
196
|
+
cd ga-cli
|
|
197
|
+
|
|
198
|
+
# Create virtual environment
|
|
199
|
+
python -m venv venv
|
|
200
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
201
|
+
|
|
202
|
+
# Install in development mode
|
|
203
|
+
pip install -e .
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Run tests
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
pytest tests/ -v
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Project Structure
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
ga-cli/
|
|
216
|
+
├── ga_cli/
|
|
217
|
+
│ ├── __init__.py
|
|
218
|
+
│ ├── cli.py # Main CLI entry point
|
|
219
|
+
│ ├── auth.py # Authentication manager
|
|
220
|
+
│ ├── config.py # Configuration manager
|
|
221
|
+
│ ├── commands/
|
|
222
|
+
│ │ ├── accounts.py # Account commands
|
|
223
|
+
│ │ ├── properties.py # Property commands
|
|
224
|
+
│ │ ├── datastreams.py # Data stream commands
|
|
225
|
+
│ │ └── config.py # Config commands
|
|
226
|
+
│ └── formatters/
|
|
227
|
+
│ ├── table.py # Table formatter
|
|
228
|
+
│ └── json.py # JSON formatter
|
|
229
|
+
├── tests/
|
|
230
|
+
├── setup.py
|
|
231
|
+
├── requirements.txt
|
|
232
|
+
└── README.md
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Requirements
|
|
236
|
+
|
|
237
|
+
- Python 3.7+
|
|
238
|
+
- Click 8.0+
|
|
239
|
+
- google-analytics-admin 0.27.0+
|
|
240
|
+
- google-auth 2.0+
|
|
241
|
+
- rich 13.0+
|
|
242
|
+
|
|
243
|
+
## License
|
|
244
|
+
|
|
245
|
+
MIT License
|
|
246
|
+
|
|
247
|
+
## Contributing
|
|
248
|
+
|
|
249
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
250
|
+
|
|
251
|
+
## Support
|
|
252
|
+
|
|
253
|
+
For issues and questions, please open an issue on GitHub.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
ga4_cli-0.1.0.dist-info/licenses/LICENSE,sha256=9vweInHjCIGx8SsP1v0L3seMYTVersqfyZZtgD0P3ho,1076
|
|
2
|
+
ga_cli/__init__.py,sha256=zmVdMQWUJADbrUqT9Rt8ok0RDO5L2oZnPFw6XAJsRN0,85
|
|
3
|
+
ga_cli/auth.py,sha256=7D_QL4FOs1SeT3Xhjn6v6D4fBu34zk9Owel1ayLUnU8,1892
|
|
4
|
+
ga_cli/cli.py,sha256=gqojzERWqVwZjdI5_H36Flfbpr6oUPvnp9y34GDPF_M,954
|
|
5
|
+
ga_cli/config.py,sha256=PSRwRJPVhH5eCTM9Hy6KR65klpeeIrOb0HXEy4sTJu8,3040
|
|
6
|
+
ga_cli/decorators.py,sha256=Qn4LfV0Xs9680KrV0lcIt73dRAiTLXEprXOVJOVBYA4,3269
|
|
7
|
+
ga_cli/errors.py,sha256=7Qkw_vjJjVdApoG8IaPe5pStHCt4Ps8sELDRAtaDkGs,1612
|
|
8
|
+
ga_cli/logging_config.py,sha256=DqW5x7-pR-LTjXH88N7TPRt4RrqG0kzTTZlEjJXE-T4,937
|
|
9
|
+
ga_cli/output.py,sha256=JyOafS8DMqLvcjfqXf9xb1YAXb5nkw9LLhGclzcPISA,1581
|
|
10
|
+
ga_cli/retry.py,sha256=WFfdGw7N5ohElUlKqOpdw2F1Y2w5uvx42pZRVkHzGy4,1432
|
|
11
|
+
ga_cli/validators.py,sha256=eDmZ_lnPInn3DNDkH-W-QUiv2C7N8qK33eZVxwEkooU,1457
|
|
12
|
+
ga_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
+
ga_cli/commands/accounts.py,sha256=WIS4liWgnmfWWh_OHO-CboheZKbCQzRt-jqOgr9EUDk,2648
|
|
14
|
+
ga_cli/commands/config.py,sha256=fjxRB8wpJ_0a01R9whThkWhO7lBN8XMiOCsa0NRgeBc,2034
|
|
15
|
+
ga_cli/commands/datastreams.py,sha256=ps_HomGWPwlAgYXt9ZLNg5R90fbUmL0VJFVk6-7yv0M,5671
|
|
16
|
+
ga_cli/commands/properties.py,sha256=tnGe4OZujpCNwWUfVseGXRThlL3mXMyUz9Zjpkka4Js,5545
|
|
17
|
+
ga_cli/formatters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
|
+
ga_cli/formatters/json.py,sha256=C1a-ghd-k7Sr7_Cmg9up96xcFueC4PgF2931pOhCcHM,145
|
|
19
|
+
ga_cli/formatters/table.py,sha256=HSwcH92wQSzgFebzr9z82NWrh27SEeD4mqj6bknhhg8,569
|
|
20
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
tests/conftest.py,sha256=jrTHupz_iYC6kdm2dpPKt7zzjwu6Udq-yqL_RUWeXRg,2618
|
|
22
|
+
tests/test_accounts.py,sha256=-7xgnqYwzj24RhZldykUkj0MEGcOlfUnd5tpPkU_1qQ,1671
|
|
23
|
+
tests/test_auth.py,sha256=UhtpUZOKWXRA6ty_3N9GHPouuZNJB1kt_2oD3BphdiM,2939
|
|
24
|
+
tests/test_cli.py,sha256=2bbcFPON-vYfdylXawIULFh-Tgs6CzsfmpubD1-OBvQ,1539
|
|
25
|
+
tests/test_config.py,sha256=Ide0_EMkVX58HIFxPuvkw3toHBKQ6n5yqjRsGVEpv9M,5406
|
|
26
|
+
tests/test_errors.py,sha256=zANsghozyAoRf4MNoIEgqlbmO_HGjBwhg_AB9hJ-eE4,3197
|
|
27
|
+
tests/test_validators.py,sha256=LO9wBHawTcn8eZ_zTIxBV7WCOSRU_Wq1UD7szwJIj0o,5176
|
|
28
|
+
ga4_cli-0.1.0.dist-info/METADATA,sha256=MUpWxfDqb3HxhVjD5FzAfEVAEP1gE7D_tiq_jeJBTnU,5909
|
|
29
|
+
ga4_cli-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
30
|
+
ga4_cli-0.1.0.dist-info/entry_points.txt,sha256=RgZTBWAkc21O2EnGi13mqHuy-ClVEffLAKW7MZ5cpdU,42
|
|
31
|
+
ga4_cli-0.1.0.dist-info/top_level.txt,sha256=8h9UkbqhP9WgaX0PfFMR5XjE1v5CcsswRYUB6ErXLE8,13
|
|
32
|
+
ga4_cli-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 GA CLI Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ga_cli/__init__.py
ADDED
ga_cli/auth.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Authentication manager for Google Analytics Admin API"""
|
|
2
|
+
|
|
3
|
+
from google.analytics.admin import AnalyticsAdminServiceClient
|
|
4
|
+
from google.oauth2 import service_account
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AuthManager:
|
|
9
|
+
"""Manages authentication for Google Analytics Admin API
|
|
10
|
+
|
|
11
|
+
This class supports context manager protocol for proper resource cleanup.
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
# Standard usage
|
|
15
|
+
auth = AuthManager(credentials_path)
|
|
16
|
+
client = auth.get_client()
|
|
17
|
+
|
|
18
|
+
# With context manager
|
|
19
|
+
with AuthManager(credentials_path) as client:
|
|
20
|
+
# Use client
|
|
21
|
+
pass
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, credentials_path=None):
|
|
25
|
+
self.credentials_path = credentials_path or os.getenv('GOOGLE_APPLICATION_CREDENTIALS')
|
|
26
|
+
self._client = None
|
|
27
|
+
|
|
28
|
+
def __enter__(self):
|
|
29
|
+
"""Context manager entry"""
|
|
30
|
+
return self.get_client()
|
|
31
|
+
|
|
32
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
33
|
+
"""Context manager exit - clean up client resources"""
|
|
34
|
+
if self._client:
|
|
35
|
+
# Close client connection
|
|
36
|
+
self._client = None
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
def get_client(self, timeout=30):
|
|
40
|
+
"""Get authenticated Analytics Admin API client
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
timeout: Request timeout in seconds (default: 30)
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
AnalyticsAdminServiceClient: Authenticated client instance
|
|
47
|
+
"""
|
|
48
|
+
if self._client is None:
|
|
49
|
+
if self.credentials_path:
|
|
50
|
+
credentials = service_account.Credentials.from_service_account_file(
|
|
51
|
+
self.credentials_path
|
|
52
|
+
)
|
|
53
|
+
self._client = AnalyticsAdminServiceClient(
|
|
54
|
+
credentials=credentials,
|
|
55
|
+
client_options={'api_endpoint': 'analyticsadmin.googleapis.com'}
|
|
56
|
+
)
|
|
57
|
+
else:
|
|
58
|
+
self._client = AnalyticsAdminServiceClient()
|
|
59
|
+
return self._client
|
ga_cli/cli.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Main CLI entry point"""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
from ga_cli import __version__
|
|
5
|
+
from ga_cli.commands.accounts import accounts
|
|
6
|
+
from ga_cli.commands.properties import properties
|
|
7
|
+
from ga_cli.commands.datastreams import datastreams
|
|
8
|
+
from ga_cli.commands.config import config
|
|
9
|
+
from ga_cli.config import ConfigManager
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@click.group()
|
|
13
|
+
@click.version_option(version=__version__)
|
|
14
|
+
@click.option('--credentials', envvar='GOOGLE_APPLICATION_CREDENTIALS',
|
|
15
|
+
help='Path to service account credentials file')
|
|
16
|
+
@click.pass_context
|
|
17
|
+
def cli(ctx, credentials):
|
|
18
|
+
"""Google Analytics CLI - Manage GA4 from the command line"""
|
|
19
|
+
ctx.ensure_object(dict)
|
|
20
|
+
|
|
21
|
+
if not credentials:
|
|
22
|
+
config_manager = ConfigManager()
|
|
23
|
+
credentials = config_manager.get_credentials_path()
|
|
24
|
+
|
|
25
|
+
ctx.obj['credentials'] = credentials
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
cli.add_command(accounts)
|
|
29
|
+
cli.add_command(properties)
|
|
30
|
+
cli.add_command(datastreams)
|
|
31
|
+
cli.add_command(config)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
if __name__ == '__main__':
|
|
35
|
+
cli()
|
|
File without changes
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Account management commands"""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
from ga_cli.decorators import with_client
|
|
5
|
+
from ga_cli.formatters.table import format_table
|
|
6
|
+
from ga_cli.formatters.json import format_json
|
|
7
|
+
from ga_cli.validators import validate_account_id
|
|
8
|
+
from ga_cli.logging_config import logger
|
|
9
|
+
from ga_cli.retry import retry_on_transient_error
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@click.group()
|
|
13
|
+
def accounts():
|
|
14
|
+
"""Manage Google Analytics accounts"""
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@accounts.command()
|
|
19
|
+
@click.option('--format', type=click.Choice(['table', 'json']), default='table')
|
|
20
|
+
@click.pass_context
|
|
21
|
+
@with_client
|
|
22
|
+
def list(ctx, format):
|
|
23
|
+
"""List all accounts"""
|
|
24
|
+
client = ctx.obj['client']
|
|
25
|
+
logger.info("Listing Google Analytics accounts")
|
|
26
|
+
|
|
27
|
+
accounts_data = []
|
|
28
|
+
for account in _list_accounts_with_retry(client):
|
|
29
|
+
accounts_data.append({
|
|
30
|
+
'id': account.name.split('/')[-1] if '/' in account.name else account.name,
|
|
31
|
+
'name': account.display_name or 'N/A',
|
|
32
|
+
'region': account.region_code or 'N/A',
|
|
33
|
+
'create_time': str(account.create_time).split('.')[0] if account.create_time else 'N/A',
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
logger.info(f"Found {len(accounts_data)} accounts")
|
|
37
|
+
|
|
38
|
+
if format == 'json':
|
|
39
|
+
format_json(accounts_data)
|
|
40
|
+
else:
|
|
41
|
+
format_table(accounts_data, title="Google Analytics Accounts")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@accounts.command()
|
|
45
|
+
@click.argument('account_id', callback=validate_account_id)
|
|
46
|
+
@click.option('--format', type=click.Choice(['table', 'json']), default='table')
|
|
47
|
+
@click.pass_context
|
|
48
|
+
@with_client
|
|
49
|
+
def get(ctx, account_id, format):
|
|
50
|
+
"""Get account details"""
|
|
51
|
+
client = ctx.obj['client']
|
|
52
|
+
logger.info(f"Getting account details for: {account_id}")
|
|
53
|
+
|
|
54
|
+
account = _get_account_with_retry(client, account_id)
|
|
55
|
+
|
|
56
|
+
account_data = {
|
|
57
|
+
'id': account.name.split('/')[-1] if '/' in account.name else account.name,
|
|
58
|
+
'name': account.display_name or 'N/A',
|
|
59
|
+
'region': account.region_code or 'N/A',
|
|
60
|
+
'create_time': str(account.create_time).split('.')[0] if account.create_time else 'N/A',
|
|
61
|
+
'update_time': str(account.update_time).split('.')[0] if account.update_time else 'N/A',
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
logger.info(f"Retrieved account: {account.display_name}")
|
|
65
|
+
|
|
66
|
+
if format == 'json':
|
|
67
|
+
format_json(account_data)
|
|
68
|
+
else:
|
|
69
|
+
format_table([account_data], title=f"Account: {account.display_name}")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@retry_on_transient_error()
|
|
73
|
+
def _list_accounts_with_retry(client):
|
|
74
|
+
"""List accounts with retry logic"""
|
|
75
|
+
return list(client.list_accounts())
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@retry_on_transient_error()
|
|
79
|
+
def _get_account_with_retry(client, account_id):
|
|
80
|
+
"""Get account with retry logic"""
|
|
81
|
+
return client.get_account(name=f"accounts/{account_id}")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Configuration commands"""
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import os
|
|
5
|
+
from ga_cli.config import ConfigManager
|
|
6
|
+
from ga_cli.auth import AuthManager
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group()
|
|
10
|
+
def config():
|
|
11
|
+
"""Manage CLI configuration"""
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@config.command()
|
|
16
|
+
@click.option('--credentials', prompt='Path to service account JSON',
|
|
17
|
+
help='Path to Google service account credentials file')
|
|
18
|
+
def init(credentials):
|
|
19
|
+
"""Initialize GA CLI with credentials"""
|
|
20
|
+
try:
|
|
21
|
+
credentials_path = os.path.expanduser(credentials)
|
|
22
|
+
|
|
23
|
+
if not os.path.exists(credentials_path):
|
|
24
|
+
click.echo(f"Error: Credentials file not found at {credentials_path}", err=True)
|
|
25
|
+
raise click.Abort()
|
|
26
|
+
|
|
27
|
+
click.echo("Testing credentials...")
|
|
28
|
+
auth = AuthManager(credentials_path)
|
|
29
|
+
client = auth.get_client()
|
|
30
|
+
|
|
31
|
+
accounts = list(client.list_accounts())
|
|
32
|
+
|
|
33
|
+
if accounts:
|
|
34
|
+
click.echo(f"Credentials valid! Found {len(accounts)} account(s)")
|
|
35
|
+
|
|
36
|
+
config_manager = ConfigManager()
|
|
37
|
+
config_manager.set_credentials_path(credentials_path)
|
|
38
|
+
|
|
39
|
+
click.echo(f"Configuration saved to {config_manager.config_file}")
|
|
40
|
+
click.echo("\nYou can now use ga-cli commands without specifying credentials")
|
|
41
|
+
else:
|
|
42
|
+
click.echo("Warning: Credentials are valid but no accounts found", err=True)
|
|
43
|
+
|
|
44
|
+
except Exception as e:
|
|
45
|
+
click.echo(f"Error: {str(e)}", err=True)
|
|
46
|
+
raise click.Abort()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@config.command()
|
|
50
|
+
def show():
|
|
51
|
+
"""Show current configuration"""
|
|
52
|
+
try:
|
|
53
|
+
config_manager = ConfigManager()
|
|
54
|
+
credentials_path = config_manager.get_credentials_path()
|
|
55
|
+
|
|
56
|
+
if credentials_path:
|
|
57
|
+
click.echo("Configuration:")
|
|
58
|
+
click.echo(f" Credentials: {credentials_path}")
|
|
59
|
+
click.echo(f" Config file: {config_manager.config_file}")
|
|
60
|
+
else:
|
|
61
|
+
click.echo("No configuration found. Run 'ga-cli config init' to set up.")
|
|
62
|
+
|
|
63
|
+
except Exception as e:
|
|
64
|
+
click.echo(f"Error: {str(e)}", err=True)
|
|
65
|
+
raise click.Abort()
|