mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
feat: hardcode Umami analytics defaults for FOSS usage tracking
Bake in cloud.umami.is host and basic-memory-foss site ID so all open-source installs send anonymous CLI events by default. Users can still opt out with BASIC_MEMORY_NO_PROMOS=1 or override the endpoint via env vars. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
@@ -6,10 +6,10 @@ no cookies. Respects the same opt-out mechanisms as promo messaging.
|
||||
|
||||
Events are fire-and-forget — analytics never blocks or breaks the CLI.
|
||||
|
||||
Setup:
|
||||
Set these environment variables (or leave unset to disable):
|
||||
BASIC_MEMORY_UMAMI_HOST — Umami instance URL (e.g. https://analytics.basicmemory.com)
|
||||
BASIC_MEMORY_UMAMI_SITE_ID — Website ID from Umami dashboard
|
||||
Defaults point to the Basic Memory Umami Cloud instance. Override via:
|
||||
BASIC_MEMORY_UMAMI_HOST — Custom Umami instance URL
|
||||
BASIC_MEMORY_UMAMI_SITE_ID — Custom Website ID
|
||||
Opt out entirely with BASIC_MEMORY_NO_PROMOS=1.
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -22,16 +22,19 @@ import basic_memory
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Configuration — read from environment so nothing is hard-coded in source
|
||||
# Configuration — defaults baked in, overridable via environment
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_DEFAULT_UMAMI_HOST = "https://cloud.umami.is"
|
||||
_DEFAULT_UMAMI_SITE_ID = "f6479898-ebaf-4e60-bce2-6dc60a3f6c5c"
|
||||
|
||||
|
||||
def _umami_host() -> Optional[str]:
|
||||
return os.getenv("BASIC_MEMORY_UMAMI_HOST", "").strip() or None
|
||||
return os.getenv("BASIC_MEMORY_UMAMI_HOST", "").strip() or _DEFAULT_UMAMI_HOST
|
||||
|
||||
|
||||
def _umami_site_id() -> Optional[str]:
|
||||
return os.getenv("BASIC_MEMORY_UMAMI_SITE_ID", "").strip() or None
|
||||
return os.getenv("BASIC_MEMORY_UMAMI_SITE_ID", "").strip() or _DEFAULT_UMAMI_SITE_ID
|
||||
|
||||
|
||||
def _analytics_disabled() -> bool:
|
||||
|
||||
+14
-13
@@ -9,6 +9,8 @@ from basic_memory.cli.analytics import (
|
||||
track,
|
||||
_analytics_disabled,
|
||||
_is_configured,
|
||||
_umami_host,
|
||||
_umami_site_id,
|
||||
EVENT_PROMO_SHOWN,
|
||||
EVENT_CLOUD_LOGIN_STARTED,
|
||||
EVENT_CLOUD_LOGIN_SUCCESS,
|
||||
@@ -37,20 +39,17 @@ class TestIsConfigured:
|
||||
monkeypatch.setenv("BASIC_MEMORY_UMAMI_SITE_ID", "abc-123")
|
||||
assert _is_configured() is True
|
||||
|
||||
def test_not_configured_when_host_missing(self, monkeypatch):
|
||||
def test_configured_by_default(self, monkeypatch):
|
||||
"""Defaults are baked in — always configured unless explicitly emptied."""
|
||||
monkeypatch.delenv("BASIC_MEMORY_UMAMI_HOST", raising=False)
|
||||
monkeypatch.setenv("BASIC_MEMORY_UMAMI_SITE_ID", "abc-123")
|
||||
assert _is_configured() is False
|
||||
|
||||
def test_not_configured_when_site_id_missing(self, monkeypatch):
|
||||
monkeypatch.setenv("BASIC_MEMORY_UMAMI_HOST", "https://analytics.example.com")
|
||||
monkeypatch.delenv("BASIC_MEMORY_UMAMI_SITE_ID", raising=False)
|
||||
assert _is_configured() is False
|
||||
assert _is_configured() is True
|
||||
|
||||
def test_not_configured_when_empty_strings(self, monkeypatch):
|
||||
monkeypatch.setenv("BASIC_MEMORY_UMAMI_HOST", "")
|
||||
monkeypatch.setenv("BASIC_MEMORY_UMAMI_SITE_ID", "")
|
||||
assert _is_configured() is False
|
||||
def test_env_override_takes_precedence(self, monkeypatch):
|
||||
monkeypatch.setenv("BASIC_MEMORY_UMAMI_HOST", "https://custom.example.com")
|
||||
monkeypatch.setenv("BASIC_MEMORY_UMAMI_SITE_ID", "custom-id")
|
||||
assert _umami_host() == "https://custom.example.com"
|
||||
assert _umami_site_id() == "custom-id"
|
||||
|
||||
|
||||
class TestTrack:
|
||||
@@ -60,13 +59,15 @@ class TestTrack:
|
||||
track("test-event")
|
||||
mock_thread.assert_not_called()
|
||||
|
||||
def test_no_op_when_not_configured(self, monkeypatch):
|
||||
def test_sends_when_using_defaults(self, monkeypatch):
|
||||
"""With baked-in defaults, track() fires even without env vars."""
|
||||
monkeypatch.delenv("BASIC_MEMORY_NO_PROMOS", raising=False)
|
||||
monkeypatch.delenv("BASIC_MEMORY_UMAMI_HOST", raising=False)
|
||||
monkeypatch.delenv("BASIC_MEMORY_UMAMI_SITE_ID", raising=False)
|
||||
with patch("basic_memory.cli.analytics.threading.Thread") as mock_thread:
|
||||
mock_thread.return_value = MagicMock()
|
||||
track("test-event")
|
||||
mock_thread.assert_not_called()
|
||||
mock_thread.assert_called_once()
|
||||
|
||||
def test_sends_event_when_configured(self, monkeypatch):
|
||||
monkeypatch.delenv("BASIC_MEMORY_NO_PROMOS", raising=False)
|
||||
|
||||
Reference in New Issue
Block a user