feat(analytics): opt-in Firebase Analytics on generated pages - #93
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cb7519c79a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
Adds an opt-in, fork-safe Firebase Analytics (GA4) snippet to the generated static mirror site by exposing a shared Jinja global that injects the module-based Firebase Analytics initialization into the <head> of all page types.
Changes:
- Implement
firebase_analytics_snippet()incore/utils.py, gated byFIREBASE_WEB_CONFIGand requiring ameasurementId, and register it as thefirebase_analytics()Jinja global. - Inject
{{ firebase_analytics() }}into post templates (file + inline fallback), index template, and comment note pages (generator template). - Wire
FIREBASE_WEB_CONFIGthrough the upstream publish workflow into the compositegenerate-siteaction, and add tests covering enabled/disabled behavior and index injection.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_core_utils.py |
Adds unit tests for analytics snippet gating and verifies index template injection. |
src/devto_mirror/templates/post_template.html |
Injects firebase_analytics() into the file-based post template head. |
src/devto_mirror/site_generation/generator.py |
Registers the Jinja global on the generator env and injects it into comment note pages (and inline post fallback in this module). |
src/devto_mirror/core/utils.py |
Implements the gated snippet builder, pins the SDK version, escapes <, returns safe Markup, and registers the Jinja global on the core env. |
.github/workflows/publish.yaml |
Documents the new repo variable and passes it into the generate-site action (upstream-only deploy). |
.github/actions/generate-site/action.yml |
Adds firebase_web_config input and forwards it to FIREBASE_WEB_CONFIG for the generator step. |
Injects the Firebase Analytics module snippet into every generated page (index, posts, comments) via a shared `firebase_analytics()` Jinja global. Gated on the FIREBASE_WEB_CONFIG env var (Firebase web config JSON): the snippet is emitted only when the config is present and carries a measurementId. Forks leave it unset and ship no analytics — mirroring the existing owner-only Firebase deploy guard. Wired through the generate-site action input and the FIREBASE_WEB_CONFIG repo variable in publish.yaml. The embedded JSON is owner-controlled repo config; '<' is escaped to neutralize any </script> breakout. Generated-by: Claude Opus 4.8 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
renderer.py is the last writer of index.html; without the env var the deployed homepage shipped without the analytics snippet while posts and comments had it. Closes a gap flagged in PR review. Generated-by: Claude Opus 4.8 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
pre-push only ran a subset (test + detect-secrets + validate-site), letting commits push without format/lint/complexity. Collapse it to `make ai-checks` so the push gate matches the manual gate exactly; detect-secrets and validate-site already run inside ai-checks. Generated-by: Claude Opus 4.8 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Ashley Childress <anchildress1@gmail.com>
pre-push now runs the slow checks not done at commit time — full tests, complexity, site validation — instead of redoing format/lint/security that pre-commit already covers. Drops detect-secrets here since pre-commit's `make security` already runs it. Generated-by: Claude Opus 4.8 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Ashley Childress <anchildress1@gmail.com>
752b938 to
180907e
Compare
What 🔧
Adds Firebase Analytics (GA4) to the generated mirror site — opt-in, fork-safe.
firebase_analytics()Jinja global injects the Firebase Analytics module snippet before</head>on every page type: index, posts (file + inline fallback), and comment pagescore/utils.py+generator.py)12.15.0(CDN ESM import — no build step needed for the static site)Fork safety 🛡️
FIREBASE_WEB_CONFIGenv var (Firebase web config JSON)measurementIdgithub.repository_owner == 'anchildress1'Firebase-deploy guardgenerate-siteaction input →publish.yamlreadsvars.FIREBASE_WEB_CONFIG;deploy-gh-pages.yml(fork path) is intentionally not wiredSecurity 🔒
<is escaped to<so a stray</script>can't break out — inert regardless of sourceVerification ✅
make ai-checks— format, lint, security, complexity, tests all pass (coverage 88.74% > 85%)test_core_utils.py: unset / invalid JSON / missing measurementId → empty; valid config → snippet + measurementId + SDK version present; end-to-end injection intoINDEX_TMPLactionlintclean onpublish.yamlThis is wired but dormant until you add the repo variable. Set
FIREBASE_WEB_CONFIG(Settings → Variables → Actions) to the JSON config — the next publish run will start emitting analytics. It's public web config, safe to store as a plain variable (not a secret).To preview locally:
export FIREBASE_WEB_CONFIG='{...}'before running the generator.🤖 Generated with Claude Code