Skip to content

Commit 3cc1d60

Browse files
Matt Van Hornfrittlechasm
authored andcommitted
fix(analytics): use official Mixpanel Go SDK and drop redundant interface test
Review feedback from @mabd-dev: 1. Swap `github.com/dukex/mixpanel` for the official `github.com/mixpanel/mixpanel-go` SDK referenced in https://docs.mixpanel.com/docs/tracking-methods/sdks/go. The official SDK exposes `NewApiClient(token)` and `Track(ctx, []*Event)` instead of the dukex SDK's `New(token, "")` / `Track(distinctID, event, *Event)`. MixpanelAnalytics now constructs events via `client.NewEvent(event, distinctID, properties)` and calls `client.Track(context.Background(), []*Event{ev})`. The Analytics interface is unchanged, so no callers are affected. Also dropped the trailing `var _ = context.Background` line - it was a placeholder for the old SDK's missing context support; the new SDK takes a real context.Context. 2. Remove `TestAnalytics_InterfaceIsSatisfied` from analytics_test.go. The `var _ Analytics = ...` declarations at the bottom of analytics.go already enforce this at compile time, so the test adds no coverage. Verified: go build ./..., go vet ./..., go test ./... all pass.
1 parent 6090f8a commit 3cc1d60

4 files changed

Lines changed: 23 additions & 31 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ require (
77
github.com/charmbracelet/bubbles v0.21.0
88
github.com/charmbracelet/bubbletea v1.3.6
99
github.com/charmbracelet/lipgloss v1.1.0
10-
github.com/dukex/mixpanel v1.0.1
1110
github.com/fatih/color v1.18.0
1211
github.com/mattn/go-runewidth v0.0.16
12+
github.com/mixpanel/mixpanel-go v1.2.1
1313
github.com/muesli/reflow v0.3.0
1414
github.com/muesli/termenv v0.16.0
1515
github.com/pelletier/go-toml/v2 v2.2.4

go.sum

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@ github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod
2323
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
2424
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
2525
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
26-
github.com/dukex/mixpanel v1.0.1 h1:IQ3qBjtgltF044jU9+i6MubdDdpc8PKpK9yvfawRgeE=
27-
github.com/dukex/mixpanel v1.0.1/go.mod h1:080BDsRRMzAxViWT3OjlQaMW9nhaIEXDHHtGeDK60b8=
26+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
27+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2828
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
2929
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
3030
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
3131
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
3232
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
3333
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
34+
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
35+
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
3436
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
3537
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
3638
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
@@ -43,6 +45,8 @@ github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+Ei
4345
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
4446
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
4547
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
48+
github.com/mixpanel/mixpanel-go v1.2.1 h1:iykbHKomTJjVoWU95Vt1sjZy4HLt8UOYacMEEEMFBok=
49+
github.com/mixpanel/mixpanel-go v1.2.1/go.mod h1:mPGaNhBoZMJuLu8k7Y1KhU5n8Vw13rxQZZjHj+b9RLk=
4650
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
4751
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
4852
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
@@ -53,6 +57,8 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc
5357
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
5458
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
5559
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
60+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
61+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5662
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
5763
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
5864
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
@@ -62,6 +68,8 @@ github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
6268
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
6369
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
6470
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
71+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
72+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
6573
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
6674
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
6775
golang.design/x/clipboard v0.7.1 h1:OEG3CmcYRBNnRwpDp7+uWLiZi3hrMRJpE9JkkkYtz2c=

internal/analytics/analytics.go

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// Callers depend only on the Analytics interface, so the rest of the codebase
44
// never imports a concrete SDK. Two implementations are provided:
55
//
6-
// - MixpanelAnalytics sends events via the Mixpanel HTTP API.
6+
// - MixpanelAnalytics sends events via the official Mixpanel Go SDK.
77
// - StdoutAnalytics prints events to stdout as JSON for local / CI use.
88
//
99
// The factory New() picks between them based on whether a build-time token is
@@ -17,7 +17,7 @@ import (
1717
"io"
1818
"os"
1919

20-
"github.com/dukex/mixpanel"
20+
mixpanel "github.com/mixpanel/mixpanel-go"
2121
)
2222

2323
// Analytics is the single entry point for emitting a usage event. A nil
@@ -52,31 +52,30 @@ func (s StdoutAnalytics) Send(event string, properties map[string]any) error {
5252
return nil
5353
}
5454

55-
// MixpanelAnalytics sends events to the Mixpanel HTTP API via the dukex/mixpanel
56-
// SDK. It uses a distinctID of "anonymous" because reposcan does not have a
57-
// persistent user identity (that is handled in the telemetry layer built on
58-
// top of this).
55+
// MixpanelAnalytics sends events to the Mixpanel HTTP API via the official
56+
// mixpanel/mixpanel-go SDK. It uses a distinctID of "anonymous" because
57+
// reposcan does not have a persistent user identity (that is handled in the
58+
// telemetry layer built on top of this).
5959
type MixpanelAnalytics struct {
60-
client mixpanel.Mixpanel
60+
client *mixpanel.ApiClient
6161
distinctID string
6262
}
6363

6464
// NewMixpanelAnalytics constructs a live client against the Mixpanel API.
6565
// The token is required; passing an empty token is a caller bug.
6666
func NewMixpanelAnalytics(token string) *MixpanelAnalytics {
6767
return &MixpanelAnalytics{
68-
client: mixpanel.New(token, ""),
68+
client: mixpanel.NewApiClient(token),
6969
distinctID: "anonymous",
7070
}
7171
}
7272

7373
// Send forwards the event to Mixpanel. Failures are returned to the caller
74-
// verbatim it is the caller's responsibility to decide whether telemetry
74+
// verbatim - it is the caller's responsibility to decide whether telemetry
7575
// failures should be logged or swallowed.
7676
func (m *MixpanelAnalytics) Send(event string, properties map[string]any) error {
77-
if err := m.client.Track(m.distinctID, event, &mixpanel.Event{
78-
Properties: properties,
79-
}); err != nil {
77+
ev := m.client.NewEvent(event, m.distinctID, properties)
78+
if err := m.client.Track(context.Background(), []*mixpanel.Event{ev}); err != nil {
8079
return fmt.Errorf("analytics: mixpanel track: %w", err)
8180
}
8281
return nil
@@ -90,7 +89,7 @@ var (
9089

9190
// New picks the implementation based on build- and run-time inputs.
9291
//
93-
// - If debug is true, events go to stdout even when a real token is wired
92+
// - If debug is true, events go to stdout - even when a real token is wired
9493
// in. This keeps local development loops noisy and predictable and mirrors
9594
// the behavior expected by CI harnesses.
9695
// - If token is empty (a local dev build without the -ldflags injection),
@@ -103,8 +102,3 @@ func New(token string, debug bool) Analytics {
103102
}
104103
return NewMixpanelAnalytics(token)
105104
}
106-
107-
// Context is accepted only to make the callsite forward-compatible with a
108-
// future version that supports cancellation and timeouts. The current
109-
// Mixpanel SDK ignores it; telemetry issue will plumb it through.
110-
var _ = context.Background

internal/analytics/analytics_test.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,3 @@ func TestNew_TokenAndNoDebugReturnsMixpanel(t *testing.T) {
8787
}
8888
}
8989

90-
func TestAnalytics_InterfaceIsSatisfied(t *testing.T) {
91-
// Compile-time: confirm both implementations satisfy the interface.
92-
// The var declarations at the bottom of analytics.go already assert
93-
// this, so this test is a belt-and-suspenders check that the tests
94-
// import the package correctly.
95-
var a Analytics
96-
a = StdoutAnalytics{}
97-
a = NewMixpanelAnalytics("x")
98-
_ = a
99-
}

0 commit comments

Comments
 (0)