Skip to content

Commit 5ac1362

Browse files
Metrics API test (#408)
* Create automate-metrics.yaml * outline for automate-metrics.yaml * Create get-metrics.py * Update automate-metrics.yaml * Update automate-metrics.yaml * Update footer-menu.html with metrics * Create metrics.md * add json_extract to extensions * Update get-metrics.py to also write file * Update get-metrics.py with returned condition * Update automate-metrics.yaml * pre-commit * use os to access passed in keys * fix double quoted strings * add jsonextract to environment.yml * write metrics.md in a python file * rm from config * use env files * update comment * state with a table * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * rm table because it won't format and add to toc tree * add dispatch * starting metrics file, and - vs _ * pre-commit * fix write-metrics --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 1b204ac commit 5ac1362

File tree

7 files changed

+176
-0
lines changed

7 files changed

+176
-0
lines changed
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Update User Metrics
2+
3+
on:
4+
workflow_dispatch:
5+
schedule:
6+
# Weekly Every Monday at 1PM UTC
7+
- cron: '0 13 * * 1'
8+
9+
env:
10+
portal_id: ${{ secrets.GA4_PORTAL_ID }}
11+
foundations_id: ${{ secrets.GA4_FOUNDATIONS_ID }}
12+
cookbooks_id: ${{ secrets.GA4_COOKBOOKS_ID }}
13+
14+
jobs:
15+
main:
16+
runs-on: macos-latest
17+
steps:
18+
- uses: actions/checkout@v3
19+
- name: Set Credentials
20+
uses: mobiledevops/secret-to-file-action@v1
21+
with:
22+
base64-encoded-secret: ${{ secrets.GOOGLE_ANALYTICS_API_CREDENTIALS }}
23+
filename: "credentials.json"
24+
is-executable: true
25+
working-directory: "."
26+
- run: export GOOGLE_APPLICATION_CREDENTIALS="credentials.json"
27+
28+
- name: Set-Up Virtual Environment
29+
run: |
30+
python -m venv analytics-api
31+
source analytics-api/bin/activate
32+
pip install google-analytics-data
33+
34+
- name: Get and Write Metrics to JSON
35+
run: python get-metrics.py
36+
37+
- name: Write Markdown File
38+
run: python write-metrics-md.py
39+
40+
- name: Push Changes
41+
if: steps.Get-and-Write-Metrics.outputs == 1 # Conditional step execution
42+
run: |
43+
git config --global user.name "${{ github.actor }}"
44+
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
45+
git add user_metrics.json
46+
git add ../portal/metrics.md
47+
git commit -m "Update user metrics"
48+
git push

.github/workflows/get-metrics.py

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import json
2+
import os
3+
4+
from google.analytics.data_v1beta import BetaAnalyticsDataClient
5+
from google.analytics.data_v1beta.types import DateRange, Metric, RunReportRequest
6+
7+
PORTAL_ID = os.environ['portal_id']
8+
FOUNDATIONS_ID = os.environ['foundations_id']
9+
COOKBOOKS_ID = os.environ['cookbook_id']
10+
11+
12+
def _run_total_users_report(property_id):
13+
"""Fetches total users for a given property ID
14+
15+
Args:
16+
property_id: The Google Analytics 4 property ID
17+
18+
Returns:
19+
int: The total number of active users
20+
"""
21+
22+
client = BetaAnalyticsDataClient()
23+
24+
request = RunReportRequest(
25+
property=f'properties/{property_id}',
26+
dimensions=[],
27+
metrics=[Metric(name='activeUsers')],
28+
date_ranges=[DateRange(start_date='2020-03-31', end_date='today')],
29+
)
30+
31+
response = client.run_report(request)
32+
33+
total_users = 0
34+
for row in response.rows:
35+
total_users += int(row.metric_values[0].value)
36+
37+
return total_users
38+
39+
40+
def get_metrics(portal_id, foundations_id, cookbooks_id):
41+
"""Retrieves total users for specified GA4 properties and writes to file if changes are significant."""
42+
43+
metrics_dict = {}
44+
metrics_dict['Portal'] = _run_total_users_report(str(portal_id))
45+
metrics_dict['Foundations'] = _run_total_users_report(str(foundations_id))
46+
metrics_dict['Cookbooks'] = _run_total_users_report(str(cookbooks_id))
47+
48+
return metrics_dict # Return the metrics dictionary
49+
50+
51+
def write_metrics(metrics_dict):
52+
"""Reads existing metrics, compares for significant change, and writes to file if necessary."""
53+
54+
# Read existing user counts (handle potential file absence)
55+
try:
56+
with open('user_metrics.json') as f:
57+
user_data = json.load(f)
58+
except FileNotFoundError:
59+
user_data = {}
60+
61+
# Define a threshold for significant change (adjust as needed)
62+
threshold = 100
63+
has_significant_change = False
64+
for property, user_count in metrics_dict.items():
65+
existing_count = user_data.get(property, 0)
66+
if abs(existing_count - user_count) > threshold:
67+
user_data[property] = user_count
68+
has_significant_change = True
69+
70+
# Write to file if significant change detected
71+
if has_significant_change:
72+
with open('user_metrics.json', 'w') as outfile:
73+
json.dump(metrics_dict, outfile)
74+
return 1 # Signals significant change
75+
else:
76+
return 0 # Signals no significant change
77+
78+
79+
if __name__ == '__main__':
80+
metrics = get_metrics(PORTAL_ID, FOUNDATIONS_ID, COOKBOOKS_ID)
81+
exit_code = write_metrics(metrics)
82+
if exit_code == 1:
83+
print('Significant change detected in user metrics.')
84+
else:
85+
print('No significant change in user metrics.')

.github/workflows/user_metrics.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"Portal": 0, "Foundations": 0, "Cookbooks": 0}

.github/workflows/write-metrics-md.py

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import json
2+
3+
4+
def process_user_data(user_data_file, markdown_file):
5+
"""
6+
Reads user data from a JSON file and writes it to a markdown file.
7+
8+
Args:
9+
user_data_file: Path to the JSON file containing user data.
10+
markdown_file: Path to the output markdown file.
11+
"""
12+
13+
with open(user_data_file, 'r') as f:
14+
user_data = json.load(f)
15+
16+
# table_header = '| Portal | Foundations | Cookbooks |\n'
17+
# table_row = f"| {' | '.join([str(user_data[key]) for key in user_data])} |\n"
18+
# table = table_header + table_row
19+
20+
# Write processed data to markdown file
21+
with open(markdown_file, 'w') as f:
22+
f.write('# Metrics \n\n')
23+
f.write('Total Users:\n\n')
24+
for key in user_data:
25+
f.write(f'{key}: {user_data[key]}\n')
26+
f.close()
27+
28+
29+
if __name__ == '__main__':
30+
user_data_file = 'user_metrics.json'
31+
markdown_file = '../../portal/metrics.md'
32+
process_user_data(user_data_file, markdown_file)
33+
print('User data report generated: ', markdown_file)

portal/_templates/footer-menu.html

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ <h1>{{ _("About") }}</h1>
88
<li><a href="https://projectpythia.org/about.html">{{ _("About Project Pythia") }}</a></li>
99
<li><a href="https://foundations.projectpythia.org/preamble/how-to-use.html">{{ _("How to use Pythia Foundations") }}</a></li>
1010
<li><a href="https://projectpythia.org/#how-to-cite">{{ _("How to Cite") }}</a></li>
11+
<li><a href="https://projectpythia.org/metrics.html">{{ _("Metrics") }}</a></li>
1112
</ul>
1213
</div>
1314
<div class="col-9 col-sm-4 col-md-4 col-lg-3 footer-menu-col">

portal/index.md

+1
Original file line numberDiff line numberDiff line change
@@ -227,4 +227,5 @@ contributing.md
227227
code_of_conduct.md
228228
cookbook-gallery.md
229229
resource-gallery.md
230+
metrics.md
230231
```

portal/metrics.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Metrics
2+
3+
Total Users:
4+
5+
Portal: 0
6+
Foundations: 0
7+
Cookbooks: 0

0 commit comments

Comments
 (0)