analytics_ops 0.1.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +47 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +67 -0
- data/LICENSE.txt +21 -0
- data/README.md +188 -0
- data/SECURITY.md +56 -0
- data/docs/api-support-matrix.md +50 -0
- data/docs/architecture.md +89 -0
- data/docs/authentication.md +86 -0
- data/docs/commands.md +112 -0
- data/docs/configuration-schema-v1.json +129 -0
- data/docs/configuration.md +167 -0
- data/docs/google-client-compatibility.md +59 -0
- data/docs/plan-format.md +89 -0
- data/docs/plan-schema-v1.json +224 -0
- data/docs/rails.md +73 -0
- data/docs/reports.md +124 -0
- data/docs/safety.md +93 -0
- data/docs/troubleshooting.md +103 -0
- data/exe/analytics-ops +6 -0
- data/lib/analytics_ops/applier.rb +52 -0
- data/lib/analytics_ops/canonical.rb +65 -0
- data/lib/analytics_ops/cli.rb +427 -0
- data/lib/analytics_ops/clients/admin.rb +446 -0
- data/lib/analytics_ops/clients/data.rb +314 -0
- data/lib/analytics_ops/configuration/document.rb +25 -0
- data/lib/analytics_ops/configuration/loader.rb +76 -0
- data/lib/analytics_ops/configuration/schema.rb +107 -0
- data/lib/analytics_ops/configuration/validator.rb +344 -0
- data/lib/analytics_ops/configuration.rb +19 -0
- data/lib/analytics_ops/desired_state.rb +40 -0
- data/lib/analytics_ops/errors.rb +31 -0
- data/lib/analytics_ops/plan.rb +551 -0
- data/lib/analytics_ops/planner.rb +233 -0
- data/lib/analytics_ops/rails/railtie.rb +65 -0
- data/lib/analytics_ops/rails.rb +5 -0
- data/lib/analytics_ops/redaction.rb +46 -0
- data/lib/analytics_ops/reports/catalog.rb +100 -0
- data/lib/analytics_ops/reports/definition.rb +226 -0
- data/lib/analytics_ops/reports/result.rb +90 -0
- data/lib/analytics_ops/reports.rb +13 -0
- data/lib/analytics_ops/resources.rb +79 -0
- data/lib/analytics_ops/snapshot.rb +45 -0
- data/lib/analytics_ops/version.rb +5 -0
- data/lib/analytics_ops/workspace.rb +212 -0
- data/lib/analytics_ops.rb +21 -0
- data/lib/generators/analytics_ops/install_generator.rb +23 -0
- data/lib/generators/analytics_ops/templates/analytics-ops +9 -0
- data/lib/generators/analytics_ops/templates/analytics_ops.yml +23 -0
- data/sig/analytics_ops.rbs +395 -0
- metadata +131 -0
data/docs/commands.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Commands
|
|
2
|
+
|
|
3
|
+
The executable is `analytics-ops`. All commands use
|
|
4
|
+
`config/analytics_ops.yml` and the `production` profile unless overridden.
|
|
5
|
+
|
|
6
|
+
```text
|
|
7
|
+
analytics-ops COMMAND [options]
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Fast examples
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
analytics-ops doctor
|
|
14
|
+
analytics-ops audit --format json
|
|
15
|
+
analytics-ops plan --output tmp/ga4-plan.json
|
|
16
|
+
analytics-ops apply tmp/ga4-plan.json
|
|
17
|
+
analytics-ops report landing_pages --format csv
|
|
18
|
+
analytics-ops realtime --format json
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Only `apply` can write to Google.
|
|
22
|
+
|
|
23
|
+
## Read-only commands
|
|
24
|
+
|
|
25
|
+
| Command | Result |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| `doctor` | Checks the local file, credentials, Admin API, Data API, property access, client versions, edit visibility, and clock |
|
|
28
|
+
| `discover` | Lists accessible account IDs, property IDs, and stream IDs |
|
|
29
|
+
| `snapshot` | Prints normalized managed remote state and its fingerprint |
|
|
30
|
+
| `audit` | Compares desired state with a fresh snapshot; exits 2 for drift |
|
|
31
|
+
| `plan` | Generates the same comparison; `--output FILE` saves its exact JSON |
|
|
32
|
+
| `verify` | Replans and exits 0 only when managed state converges |
|
|
33
|
+
| `report NAME` | Runs one built-in standard Data API report |
|
|
34
|
+
| `realtime [NAME]` | Runs `realtime_events` by default |
|
|
35
|
+
| `schema` | Prints the version-1 configuration schema |
|
|
36
|
+
|
|
37
|
+
`doctor` cannot reliably inspect scopes inside an issued Google token. It
|
|
38
|
+
reports that check as unknown and proves effective access with real read-only
|
|
39
|
+
calls instead.
|
|
40
|
+
|
|
41
|
+
## Apply
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
analytics-ops apply PLAN_FILE
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Interactive apply:
|
|
48
|
+
|
|
49
|
+
1. Loads and strictly validates the saved plan.
|
|
50
|
+
2. Prints every saved before value, after value, and rollback instruction.
|
|
51
|
+
3. Requires the exact response `yes`.
|
|
52
|
+
4. Refreshes the remote snapshot.
|
|
53
|
+
5. Rejects the plan if its fingerprint is stale.
|
|
54
|
+
6. Executes only its saved create/update operations, stopping on first failure.
|
|
55
|
+
|
|
56
|
+
Automation must be explicit:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
analytics-ops apply tmp/ga4-plan.json --non-interactive --yes --format json
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`--non-interactive` without `--yes` is an error. There is no command that
|
|
63
|
+
plans and applies in one step.
|
|
64
|
+
|
|
65
|
+
## Options
|
|
66
|
+
|
|
67
|
+
| Option | Meaning |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| `-c, --config PATH` | Configuration file |
|
|
70
|
+
| `-p, --profile NAME` | Profile inside the file |
|
|
71
|
+
| `-f, --format FORMAT` | `human`, `json`, or report-only `csv` |
|
|
72
|
+
| `-o, --output PATH` | Save generated JSON; valid only with `plan` |
|
|
73
|
+
| `--transport grpc|rest` | Official Google-client transport |
|
|
74
|
+
| `--timeout SECONDS` | Positive API call timeout |
|
|
75
|
+
| `--log-level LEVEL` | Structured request metadata: `debug`, `info`, `warn`, or `error`; default `warn` |
|
|
76
|
+
| `--yes` | Approve every operation in a saved plan; apply only |
|
|
77
|
+
| `--non-interactive` | Never prompt; apply only and requires `--yes` |
|
|
78
|
+
|
|
79
|
+
Unknown arguments and options fail instead of being ignored. CSV is rejected
|
|
80
|
+
for anything except report results. CSV cells beginning with spreadsheet
|
|
81
|
+
formula characters are prefixed safely.
|
|
82
|
+
|
|
83
|
+
## Output
|
|
84
|
+
|
|
85
|
+
- Human output is readable in a terminal.
|
|
86
|
+
- JSON output uses stable gem-owned fields and structured errors.
|
|
87
|
+
- CSV contains report headers and rows only; it never applies to plans,
|
|
88
|
+
snapshots, or errors.
|
|
89
|
+
|
|
90
|
+
No command prints credentials or generated Google protobuf objects. Report
|
|
91
|
+
rows are emitted only because the user requested a report; they are never
|
|
92
|
+
logged automatically.
|
|
93
|
+
|
|
94
|
+
## Exit statuses
|
|
95
|
+
|
|
96
|
+
| Status | Meaning |
|
|
97
|
+
| ---: | --- |
|
|
98
|
+
| 0 | Success |
|
|
99
|
+
| 2 | Drift found or verification not converged |
|
|
100
|
+
| 64 | Invalid command, option, argument, or missing confirmation |
|
|
101
|
+
| 65 | Invalid configuration, plan, or ambiguous identity |
|
|
102
|
+
| 66 | Authentication failure |
|
|
103
|
+
| 69 | Invalid Google request or other remote API failure |
|
|
104
|
+
| 74 | Timeout |
|
|
105
|
+
| 75 | Quota or rate limit |
|
|
106
|
+
| 77 | Google Analytics permission failure |
|
|
107
|
+
| 78 | Unsupported installed-client capability |
|
|
108
|
+
| 79 | Stale saved plan |
|
|
109
|
+
| 80 | Partial apply; inspect reconciliation output |
|
|
110
|
+
|
|
111
|
+
When `--format json` is selected, errors are JSON on standard error and are
|
|
112
|
+
suitable for automation.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/nelsonchaves/analytics_ops/blob/master/docs/configuration-schema-v1.json",
|
|
4
|
+
"title": "Analytics Ops configuration version 1",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["version", "profiles"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"version": { "const": 1 },
|
|
10
|
+
"profiles": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"minProperties": 1,
|
|
13
|
+
"propertyNames": { "pattern": "^[A-Za-z][A-Za-z0-9_]{0,63}$" },
|
|
14
|
+
"additionalProperties": { "$ref": "#/$defs/profile" }
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"$defs": {
|
|
18
|
+
"id": {
|
|
19
|
+
"type": "string",
|
|
20
|
+
"pattern": "^(?:[0-9]{1,50}|\\$\\{[A-Z][A-Z0-9_]*\\})$"
|
|
21
|
+
},
|
|
22
|
+
"profile": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"additionalProperties": false,
|
|
25
|
+
"required": ["property_id"],
|
|
26
|
+
"properties": {
|
|
27
|
+
"property_id": { "$ref": "#/$defs/id" },
|
|
28
|
+
"streams": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"propertyNames": { "pattern": "^[A-Za-z][A-Za-z0-9_]{0,63}$" },
|
|
31
|
+
"additionalProperties": { "$ref": "#/$defs/stream" }
|
|
32
|
+
},
|
|
33
|
+
"retention": { "$ref": "#/$defs/retention" },
|
|
34
|
+
"google_signals": { "$ref": "#/$defs/googleSignals" },
|
|
35
|
+
"key_events": {
|
|
36
|
+
"type": "array",
|
|
37
|
+
"uniqueItems": true,
|
|
38
|
+
"items": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_]{0,39}$" }
|
|
39
|
+
},
|
|
40
|
+
"custom_dimensions": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": { "$ref": "#/$defs/customDimension" }
|
|
43
|
+
},
|
|
44
|
+
"custom_metrics": {
|
|
45
|
+
"type": "array",
|
|
46
|
+
"items": { "$ref": "#/$defs/customMetric" }
|
|
47
|
+
},
|
|
48
|
+
"manual_requirements": {
|
|
49
|
+
"type": "array",
|
|
50
|
+
"uniqueItems": true,
|
|
51
|
+
"items": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_]{0,63}$" }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"stream": {
|
|
56
|
+
"type": "object",
|
|
57
|
+
"additionalProperties": false,
|
|
58
|
+
"required": ["stream_id"],
|
|
59
|
+
"properties": {
|
|
60
|
+
"stream_id": { "$ref": "#/$defs/id" },
|
|
61
|
+
"default_uri": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"maxLength": 2048,
|
|
64
|
+
"pattern": "^(?:https?://|\\$\\{)"
|
|
65
|
+
},
|
|
66
|
+
"enhanced_measurement": {
|
|
67
|
+
"type": "object",
|
|
68
|
+
"additionalProperties": false,
|
|
69
|
+
"required": ["enabled", "experimental"],
|
|
70
|
+
"properties": {
|
|
71
|
+
"enabled": { "type": "boolean" },
|
|
72
|
+
"experimental": { "const": true }
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"retention": {
|
|
78
|
+
"type": "object",
|
|
79
|
+
"additionalProperties": false,
|
|
80
|
+
"required": ["event_data", "user_data", "reset_on_new_activity"],
|
|
81
|
+
"properties": {
|
|
82
|
+
"event_data": { "$ref": "#/$defs/retentionValue" },
|
|
83
|
+
"user_data": { "$ref": "#/$defs/retentionValue" },
|
|
84
|
+
"reset_on_new_activity": { "type": "boolean" }
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"retentionValue": {
|
|
88
|
+
"enum": ["2_months", "14_months", "26_months", "38_months", "50_months"]
|
|
89
|
+
},
|
|
90
|
+
"googleSignals": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"additionalProperties": false,
|
|
93
|
+
"required": ["state", "experimental"],
|
|
94
|
+
"properties": {
|
|
95
|
+
"state": { "enum": ["enabled", "disabled"] },
|
|
96
|
+
"experimental": { "const": true }
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"customDimension": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"additionalProperties": false,
|
|
102
|
+
"required": ["parameter_name", "display_name", "scope"],
|
|
103
|
+
"properties": {
|
|
104
|
+
"parameter_name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_]{0,39}$" },
|
|
105
|
+
"display_name": { "type": "string", "minLength": 1, "maxLength": 82 },
|
|
106
|
+
"description": { "type": "string", "maxLength": 150 },
|
|
107
|
+
"scope": { "enum": ["event", "user", "item"] },
|
|
108
|
+
"disallow_ads_personalization": { "type": "boolean" }
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"customMetric": {
|
|
112
|
+
"type": "object",
|
|
113
|
+
"additionalProperties": false,
|
|
114
|
+
"required": ["parameter_name", "display_name", "scope"],
|
|
115
|
+
"properties": {
|
|
116
|
+
"parameter_name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_]{0,39}$" },
|
|
117
|
+
"display_name": { "type": "string", "minLength": 1, "maxLength": 82 },
|
|
118
|
+
"description": { "type": "string", "maxLength": 150 },
|
|
119
|
+
"scope": { "const": "event" },
|
|
120
|
+
"measurement_unit": {
|
|
121
|
+
"enum": [
|
|
122
|
+
"standard", "currency", "feet", "meters", "kilometers", "miles",
|
|
123
|
+
"milliseconds", "seconds", "minutes", "hours"
|
|
124
|
+
]
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Analytics Ops reads strict, versioned YAML. The file describes desired GA4
|
|
4
|
+
state; it never contains credentials.
|
|
5
|
+
|
|
6
|
+
## Smallest valid file
|
|
7
|
+
|
|
8
|
+
```yaml
|
|
9
|
+
version: 1
|
|
10
|
+
|
|
11
|
+
profiles:
|
|
12
|
+
production:
|
|
13
|
+
property_id: "123456789"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Numeric identifiers must stay quoted. `property_id` is a GA4 property ID,
|
|
17
|
+
not account ID `100000001`, stream ID `987654321`, or measurement ID
|
|
18
|
+
`G-EXAMPLE1`.
|
|
19
|
+
|
|
20
|
+
Use it with:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
analytics-ops doctor
|
|
24
|
+
analytics-ops audit
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
The default path is `config/analytics_ops.yml`; the default profile is
|
|
28
|
+
`production`. Change them with `--config` and `--profile`.
|
|
29
|
+
|
|
30
|
+
## Complete example
|
|
31
|
+
|
|
32
|
+
All identifiers below are fake:
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
version: 1
|
|
36
|
+
|
|
37
|
+
profiles:
|
|
38
|
+
production:
|
|
39
|
+
property_id: "${GA4_PROPERTY_ID}"
|
|
40
|
+
|
|
41
|
+
streams:
|
|
42
|
+
web:
|
|
43
|
+
stream_id: "${GA4_STREAM_ID}"
|
|
44
|
+
default_uri: "https://www.example.test"
|
|
45
|
+
|
|
46
|
+
# Accepted only as an explicit experimental declaration.
|
|
47
|
+
# Version 0.1.0 reports a finding and does not apply this setting.
|
|
48
|
+
enhanced_measurement:
|
|
49
|
+
enabled: true
|
|
50
|
+
experimental: true
|
|
51
|
+
|
|
52
|
+
retention:
|
|
53
|
+
event_data: 14_months
|
|
54
|
+
user_data: 14_months
|
|
55
|
+
reset_on_new_activity: false
|
|
56
|
+
|
|
57
|
+
key_events:
|
|
58
|
+
- calculation_completed
|
|
59
|
+
|
|
60
|
+
custom_dimensions:
|
|
61
|
+
- parameter_name: calculator_slug
|
|
62
|
+
display_name: Calculator slug
|
|
63
|
+
description: Published calculator identifier
|
|
64
|
+
scope: event
|
|
65
|
+
|
|
66
|
+
- parameter_name: customer_segment
|
|
67
|
+
display_name: Customer segment
|
|
68
|
+
description: Broad non-sensitive segment
|
|
69
|
+
scope: user
|
|
70
|
+
disallow_ads_personalization: true
|
|
71
|
+
|
|
72
|
+
custom_metrics:
|
|
73
|
+
- parameter_name: estimate_total
|
|
74
|
+
display_name: Estimate total
|
|
75
|
+
description: Non-sensitive calculated estimate
|
|
76
|
+
scope: event
|
|
77
|
+
measurement_unit: currency
|
|
78
|
+
|
|
79
|
+
# Checklist findings only; Analytics Ops does not claim to manage these.
|
|
80
|
+
manual_requirements:
|
|
81
|
+
- email_redaction_enabled
|
|
82
|
+
- consent_mode_reviewed
|
|
83
|
+
|
|
84
|
+
# Explicit declaration only in 0.1.0; never silently applied.
|
|
85
|
+
google_signals:
|
|
86
|
+
state: disabled
|
|
87
|
+
experimental: true
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Managed fields
|
|
91
|
+
|
|
92
|
+
### Streams
|
|
93
|
+
|
|
94
|
+
`streams` is keyed by a local readable name. Each entry requires a numeric
|
|
95
|
+
`stream_id`. For a web stream, `default_uri` may be an absolute HTTP or
|
|
96
|
+
HTTPS URI without embedded credentials. Analytics Ops can update an existing
|
|
97
|
+
web stream URI; it does not automatically create or delete streams.
|
|
98
|
+
|
|
99
|
+
### Retention
|
|
100
|
+
|
|
101
|
+
All three fields are required when `retention` is present:
|
|
102
|
+
|
|
103
|
+
- `event_data`: `2_months`, `14_months`, `26_months`, `38_months`, or
|
|
104
|
+
`50_months`
|
|
105
|
+
- `user_data`: the same values
|
|
106
|
+
- `reset_on_new_activity`: `true` or `false`
|
|
107
|
+
|
|
108
|
+
Google may restrict longer periods by property type or account capabilities.
|
|
109
|
+
An API rejection is returned as a typed error; Analytics Ops does not silently
|
|
110
|
+
substitute a different period.
|
|
111
|
+
|
|
112
|
+
### Key events
|
|
113
|
+
|
|
114
|
+
`key_events` is a unique list of event names. Missing events are created with
|
|
115
|
+
`once_per_event` counting. Existing key events are not deleted or renamed.
|
|
116
|
+
|
|
117
|
+
### Custom dimensions
|
|
118
|
+
|
|
119
|
+
Required fields are `parameter_name`, `display_name`, and `scope`.
|
|
120
|
+
Supported scopes are `event`, `user`, and `item`.
|
|
121
|
+
`disallow_ads_personalization` is valid only for user-scoped dimensions.
|
|
122
|
+
|
|
123
|
+
Identity is `scope + parameter_name`; display name and description are
|
|
124
|
+
mutable. Immutable conflicts are findings, not automatic replacement.
|
|
125
|
+
|
|
126
|
+
### Custom metrics
|
|
127
|
+
|
|
128
|
+
Required fields are `parameter_name`, `display_name`, and
|
|
129
|
+
`scope: event`. Units are:
|
|
130
|
+
|
|
131
|
+
`standard`, `currency`, `feet`, `meters`, `kilometers`, `miles`,
|
|
132
|
+
`milliseconds`, `seconds`, `minutes`, and `hours`.
|
|
133
|
+
|
|
134
|
+
Identity is `parameter_name`. Scope and unit are immutable; Analytics Ops
|
|
135
|
+
will not archive and recreate a conflicting metric.
|
|
136
|
+
|
|
137
|
+
## Environment variables
|
|
138
|
+
|
|
139
|
+
Only the literal form `${UPPER_CASE_NAME}` is expanded, and interpolation
|
|
140
|
+
happens after safe YAML parsing:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
export GA4_PROPERTY_ID=123456789
|
|
144
|
+
export GA4_STREAM_ID=987654321
|
|
145
|
+
analytics-ops doctor
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Missing or malformed variables fail validation. There is no ERB, command
|
|
149
|
+
execution, YAML alias support, or Ruby-object deserialization.
|
|
150
|
+
|
|
151
|
+
## Strict safety rules
|
|
152
|
+
|
|
153
|
+
- The file is limited to 1 MiB.
|
|
154
|
+
- Unknown fields fail closed.
|
|
155
|
+
- Secret-shaped fields fail closed at any depth.
|
|
156
|
+
- Numeric identifiers must be YAML strings.
|
|
157
|
+
- User-visible strings reject control characters.
|
|
158
|
+
- Duplicate resource identities fail validation.
|
|
159
|
+
- Configuration loading never contacts Google.
|
|
160
|
+
|
|
161
|
+
The machine-readable contract is
|
|
162
|
+
[configuration-schema-v1.json](configuration-schema-v1.json). Print the same
|
|
163
|
+
schema from the installed gem with:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
analytics-ops schema --format json
|
|
167
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Google client compatibility
|
|
2
|
+
|
|
3
|
+
Analytics Ops uses only Google's official modern Ruby clients. It adds no
|
|
4
|
+
second HTTP stack and does not expose generated Google objects publicly.
|
|
5
|
+
|
|
6
|
+
## Supported versions
|
|
7
|
+
|
|
8
|
+
| Direct dependency | Constraint | Contract-tested release |
|
|
9
|
+
| --- | --- | --- |
|
|
10
|
+
| `google-analytics-admin` | `~> 0.8.0` | 0.8.0 |
|
|
11
|
+
| `google-analytics-data` | `~> 0.9.0` | 0.9.0 |
|
|
12
|
+
|
|
13
|
+
The reviewed lockfile resolves these generated transports:
|
|
14
|
+
|
|
15
|
+
| Versioned transport | Reviewed release |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `google-analytics-admin-v1alpha` | 0.43.0 |
|
|
18
|
+
| `google-analytics-data-v1beta` | 0.22.0 |
|
|
19
|
+
|
|
20
|
+
The main Admin wrapper currently selects a V1alpha generated transport. That
|
|
21
|
+
transport name does not make every feature Alpha: Google publishes feature
|
|
22
|
+
maturity separately. Analytics Ops treats capabilities Google identifies as
|
|
23
|
+
Alpha as experimental or unsupported.
|
|
24
|
+
|
|
25
|
+
The pessimistic direct bounds allow reviewed patch updates inside each minor
|
|
26
|
+
line and reject a new minor contract automatically. `doctor` reports the
|
|
27
|
+
installed direct versions, expected bounds, and selected `grpc` or `rest`
|
|
28
|
+
transport.
|
|
29
|
+
|
|
30
|
+
## Executable contract coverage
|
|
31
|
+
|
|
32
|
+
Tests coerce deterministic fake requests and responses through official
|
|
33
|
+
protobuf classes for:
|
|
34
|
+
|
|
35
|
+
- `list_account_summaries`
|
|
36
|
+
- `get_property`
|
|
37
|
+
- `list_data_streams`
|
|
38
|
+
- `get_data_retention_settings`
|
|
39
|
+
- `update_data_retention_settings`
|
|
40
|
+
- `list_key_events` and `create_key_event`
|
|
41
|
+
- list/create/update custom dimensions
|
|
42
|
+
- list/create/update custom metrics
|
|
43
|
+
- update web data-stream default URI
|
|
44
|
+
- `run_report` and `run_realtime_report`
|
|
45
|
+
|
|
46
|
+
The tests also prove enum mappings and normalization into immutable gem-owned
|
|
47
|
+
values without making network requests.
|
|
48
|
+
|
|
49
|
+
## Updating a Google client
|
|
50
|
+
|
|
51
|
+
1. Review the official release and Admin API changelog.
|
|
52
|
+
2. Update one direct bound intentionally.
|
|
53
|
+
3. Resolve the lockfile on every supported Ruby.
|
|
54
|
+
4. Run focused Admin/Data contract specs.
|
|
55
|
+
5. Run the full Ruby and Rails CI matrix.
|
|
56
|
+
6. Update this file and the changelog.
|
|
57
|
+
|
|
58
|
+
Do not merge an automated client update based only on dependency resolution.
|
|
59
|
+
Generated method, field, enum, and transport changes require contract review.
|
data/docs/plan-format.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Saved plan format
|
|
2
|
+
|
|
3
|
+
`analytics-ops plan --output FILE` writes deterministic version-1 JSON. This
|
|
4
|
+
file is the only mutation input accepted by `apply`.
|
|
5
|
+
|
|
6
|
+
Example with fake identifiers:
|
|
7
|
+
|
|
8
|
+
```json
|
|
9
|
+
{
|
|
10
|
+
"changes": [
|
|
11
|
+
{
|
|
12
|
+
"after": {
|
|
13
|
+
"description": "Published calculator identifier",
|
|
14
|
+
"disallow_ads_personalization": false,
|
|
15
|
+
"display_name": "Calculator slug",
|
|
16
|
+
"parameter_name": "calculator_slug",
|
|
17
|
+
"scope": "event"
|
|
18
|
+
},
|
|
19
|
+
"api_maturity": "beta",
|
|
20
|
+
"before": null,
|
|
21
|
+
"operation": "create",
|
|
22
|
+
"resource_identity": "event:calculator_slug",
|
|
23
|
+
"resource_type": "custom_dimension",
|
|
24
|
+
"reversible": true,
|
|
25
|
+
"rollback": "Archive the newly created custom dimension"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"findings": [],
|
|
29
|
+
"format_version": 1,
|
|
30
|
+
"profile": "production",
|
|
31
|
+
"property_id": "123456789",
|
|
32
|
+
"snapshot_fingerprint": "sha256:0000000000000000000000000000000000000000000000000000000000000000"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Plans contain no timestamp. The same desired state and normalized snapshot
|
|
37
|
+
produce the same bytes.
|
|
38
|
+
|
|
39
|
+
## Top-level fields
|
|
40
|
+
|
|
41
|
+
| Field | Meaning |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `format_version` | Exact plan contract version; currently 1 |
|
|
44
|
+
| `profile` | Configuration profile that produced the plan |
|
|
45
|
+
| `property_id` | Numeric GA4 property ID encoded as a string |
|
|
46
|
+
| `snapshot_fingerprint` | SHA-256 of relevant normalized remote state |
|
|
47
|
+
| `changes` | Sorted supported create/update operations |
|
|
48
|
+
| `findings` | Sorted drift, manual, warning, or experimental observations |
|
|
49
|
+
|
|
50
|
+
Every change records resource type, stable identity, operation, API maturity,
|
|
51
|
+
before/after payloads, reversibility, and manual rollback guidance.
|
|
52
|
+
|
|
53
|
+
## Supported version-1 changes
|
|
54
|
+
|
|
55
|
+
| Resource | Create | Update | Delete/archive |
|
|
56
|
+
| --- | :---: | :---: | :---: |
|
|
57
|
+
| Existing web data-stream default URI | No | Yes | No |
|
|
58
|
+
| Data retention | No | Yes | No |
|
|
59
|
+
| Key event | Yes | No | No |
|
|
60
|
+
| Custom dimension | Yes | Mutable metadata only | No |
|
|
61
|
+
| Custom metric | Yes | Mutable metadata only | No |
|
|
62
|
+
|
|
63
|
+
Resource names in update payloads must belong to the plan's property. Immutable
|
|
64
|
+
identity fields cannot change between `before` and `after`.
|
|
65
|
+
|
|
66
|
+
## Findings are not operations
|
|
67
|
+
|
|
68
|
+
A finding may identify inaccessible resources, immutable conflicts, manual UI
|
|
69
|
+
checks, or explicitly declared experimental capabilities. Apply ignores
|
|
70
|
+
findings; it never converts them into mutations.
|
|
71
|
+
|
|
72
|
+
## Storage and review
|
|
73
|
+
|
|
74
|
+
Plan writes are atomic and mode 0600. Treat the file as operationally
|
|
75
|
+
sensitive even though credentials and report rows are forbidden:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
analytics-ops plan --output tmp/ga4-plan.json
|
|
79
|
+
less tmp/ga4-plan.json
|
|
80
|
+
analytics-ops apply tmp/ga4-plan.json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Do not hand-edit a fingerprint or payload. Generate a new plan after any remote
|
|
84
|
+
or desired-state change. Partial apply also requires reconciliation and a new
|
|
85
|
+
plan.
|
|
86
|
+
|
|
87
|
+
The complete machine-readable contract is
|
|
88
|
+
[plan-schema-v1.json](plan-schema-v1.json). Runtime validation additionally
|
|
89
|
+
enforces cross-field identity, immutable-field, and cross-property rules.
|