From e95965ae8a9cb13b33da0bc880079d582456afe9 Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Mon, 29 Apr 2024 15:06:45 -0700 Subject: [PATCH 1/7] boiler plate and track when step 1 starts --- cmd/quickstart.go | 6 +++- cmd/root.go | 2 +- internal/analytics/client.go | 48 ++++++++++++++++++++++++++++++++ internal/quickstart/container.go | 13 ++++++++- internal/quickstart/messages.go | 11 ++++++++ 5 files changed, 77 insertions(+), 3 deletions(-) diff --git a/cmd/quickstart.go b/cmd/quickstart.go index 51a38f67..9e3dd2ef 100644 --- a/cmd/quickstart.go +++ b/cmd/quickstart.go @@ -11,25 +11,28 @@ import ( "ldcli/cmd/cliflags" "ldcli/cmd/validators" + "ldcli/internal/analytics" "ldcli/internal/environments" "ldcli/internal/flags" "ldcli/internal/quickstart" ) func NewQuickStartCmd( + analyticsTracker analytics.Tracker, environmentsClient environments.Client, flagsClient flags.Client, ) *cobra.Command { return &cobra.Command{ Args: validators.Validate(), Long: "", - RunE: runQuickStart(environmentsClient, flagsClient), + RunE: runQuickStart(analyticsTracker, environmentsClient, flagsClient), Short: "Setup guide to create your first feature flag", Use: "setup", } } func runQuickStart( + analyticsTracker analytics.Tracker, environmentsClient environments.Client, flagsClient flags.Client, ) func(*cobra.Command, []string) error { @@ -42,6 +45,7 @@ func runQuickStart( defer f.Close() _, err = tea.NewProgram(quickstart.NewContainerModel( + analyticsTracker, environmentsClient, flagsClient, viper.GetString(cliflags.AccessTokenFlag), diff --git a/cmd/root.go b/cmd/root.go index 2e922b8b..5f353066 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -142,7 +142,7 @@ func NewRootCommand( cmd.AddCommand(flagsCmd) cmd.AddCommand(membersCmd) cmd.AddCommand(projectsCmd) - cmd.AddCommand(NewQuickStartCmd(clients.EnvironmentsClient, clients.FlagsClient)) + cmd.AddCommand(NewQuickStartCmd(analyticsTracker, clients.EnvironmentsClient, clients.FlagsClient)) addAllResourceCmds(cmd, clients.GenericClient, analyticsTracker) diff --git a/internal/analytics/client.go b/internal/analytics/client.go index 0bce52c3..b5357ca9 100644 --- a/internal/analytics/client.go +++ b/internal/analytics/client.go @@ -24,6 +24,12 @@ type Tracker interface { optOut bool, outcome string, ) + SendSetupStartedEvent( + accessToken, + baseURI string, + optOut bool, + step string, + ) } type Client struct { @@ -128,6 +134,23 @@ func (c *Client) SendCommandCompletedEvent( } } +func (c *Client) SendSetupStartedEvent( + accessToken, + baseURI string, + optOut bool, + step string, +) { + c.sendEvent( + accessToken, + baseURI, + optOut, + "CLI Setup Started", + map[string]interface{}{ + "step": step, + }, + ) +} + func (a *Client) Wait() { a.wg.Wait() } @@ -150,6 +173,14 @@ func (c *NoopClient) SendCommandCompletedEvent( ) { } +func (c *NoopClient) SendSetupStartedEvent( + accessToken, + baseURI string, + optOut bool, + step string, +) { +} + type MockTracker struct { mock.Mock ID string @@ -197,3 +228,20 @@ func (m *MockTracker) SendCommandCompletedEvent( }, ) } + +func (m *MockTracker) SendSetupStartedEvent( + accessToken, + baseURI string, + optOut bool, + step string, +) { + m.sendEvent( + accessToken, + baseURI, + optOut, + "CLI Setup Started", + map[string]interface{}{ + "step": step, + }, + ) +} diff --git a/internal/quickstart/container.go b/internal/quickstart/container.go index 9562bc50..d6e82770 100644 --- a/internal/quickstart/container.go +++ b/internal/quickstart/container.go @@ -8,7 +8,10 @@ import ( "github.com/charmbracelet/bubbles/spinner" tea "github.com/charmbracelet/bubbletea" "github.com/muesli/reflow/wordwrap" + "github.com/spf13/viper" + "ldcli/cmd/cliflags" + "ldcli/internal/analytics" "ldcli/internal/environments" "ldcli/internal/flags" ) @@ -30,6 +33,7 @@ const ( // represents a step in the quick-start flow. type ContainerModel struct { accessToken string + analyticsTracker analytics.Tracker baseUri string currentModel tea.Model currentStep int @@ -46,6 +50,7 @@ type ContainerModel struct { } func NewContainerModel( + analyticsTracker analytics.Tracker, environmentsClient environments.Client, flagsClient flags.Client, accessToken string, @@ -64,7 +69,13 @@ func NewContainerModel( } func (m ContainerModel) Init() tea.Cmd { - return nil + return trackSetupStartedEvent( + m.analyticsTracker, + m.accessToken, + m.baseUri, + viper.GetBool(cliflags.AnalyticsOptOut), + "1 - feature flag name", + ) } func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { diff --git a/internal/quickstart/messages.go b/internal/quickstart/messages.go index d0cb77b9..c6ef6515 100644 --- a/internal/quickstart/messages.go +++ b/internal/quickstart/messages.go @@ -7,6 +7,7 @@ import ( tea "github.com/charmbracelet/bubbletea" + "ldcli/internal/analytics" "ldcli/internal/environments" "ldcli/internal/errors" "ldcli/internal/flags" @@ -240,3 +241,13 @@ func selectedSDK(index int) tea.Cmd { return selectedSDKMsg{index: index} } } + +type eventTrackedMsg struct{} + +func trackSetupStartedEvent(tracker analytics.Tracker, accessToken, baseURI string, optOut bool, step string) tea.Cmd { + return func() tea.Msg { + tracker.SendSetupStartedEvent(accessToken, baseURI, optOut, step) + + return eventTrackedMsg{} + } +} From e92cc152f005255f2c9f461de91bf70432dc18f1 Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Mon, 29 Apr 2024 15:24:07 -0700 Subject: [PATCH 2/7] add all setup started event tracking --- internal/quickstart/container.go | 37 +++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/internal/quickstart/container.go b/internal/quickstart/container.go index d6e82770..d64d9462 100644 --- a/internal/quickstart/container.go +++ b/internal/quickstart/container.go @@ -21,14 +21,20 @@ const ( defaultEnvKey = "test" ) +type step int + const ( - _ = iota + _ step = iota stepCreateFlag stepChooseSDK stepShowSDKInstructions stepToggleFlag ) +func (s step) String() string { + return [...]string{"_", "1 - feature flag name", "2 - sdk selection", "3 - sdk installation", "4 - flag toggle"}[s] +} + // ContainerModel is a high level container model that controls the nested models where each // represents a step in the quick-start flow. type ContainerModel struct { @@ -36,7 +42,7 @@ type ContainerModel struct { analyticsTracker analytics.Tracker baseUri string currentModel tea.Model - currentStep int + currentStep step environment *environment environmentsClient environments.Client err error @@ -74,12 +80,13 @@ func (m ContainerModel) Init() tea.Cmd { m.accessToken, m.baseUri, viper.GetBool(cliflags.AnalyticsOptOut), - "1 - feature flag name", + m.currentStep.String(), ) } func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmd tea.Cmd + var sendEvent bool switch msg := msg.(type) { case tea.WindowSizeMsg: m.width = msg.Width @@ -114,11 +121,18 @@ func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.environment, ) cmd = m.currentModel.Init() + sendEvent = true } default: // delegate all other input to the current model m.currentModel, cmd = m.currentModel.Update(msg) } + case confirmedFlagMsg: + m.currentModel = NewChooseSDKModel(0) + m.flagKey = msg.flag.key + m.currentStep += 1 + m.err = nil + sendEvent = true case choseSDKMsg: m.currentModel = NewShowSDKInstructionsModel( m.environmentsClient, @@ -133,11 +147,7 @@ func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmd = m.currentModel.Init() m.sdk = msg.sdk m.currentStep += 1 - case confirmedFlagMsg: - m.currentModel = NewChooseSDKModel(0) - m.flagKey = msg.flag.key - m.currentStep += 1 - m.err = nil + sendEvent = true case errMsg: m.currentModel, cmd = m.currentModel.Update(msg) case fetchedEnvMsg: @@ -161,10 +171,21 @@ func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { ) cmd = m.currentModel.Init() m.currentStep += 1 + sendEvent = true default: log.Printf("container default: %T\n", msg) } + if sendEvent { + cmd = tea.Batch(cmd, trackSetupStartedEvent( + m.analyticsTracker, + m.accessToken, + m.baseUri, + viper.GetBool(cliflags.AnalyticsOptOut), + m.currentStep.String(), + )) + } + return m, cmd } From 5891ef6998116f01ed74679fe99fd8e04f6dca10 Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Tue, 30 Apr 2024 11:34:21 -0700 Subject: [PATCH 3/7] rename event --- internal/analytics/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/analytics/client.go b/internal/analytics/client.go index b5357ca9..13d37ddf 100644 --- a/internal/analytics/client.go +++ b/internal/analytics/client.go @@ -144,7 +144,7 @@ func (c *Client) SendSetupStartedEvent( accessToken, baseURI, optOut, - "CLI Setup Started", + "CLI Setup Step Started", map[string]interface{}{ "step": step, }, @@ -239,7 +239,7 @@ func (m *MockTracker) SendSetupStartedEvent( accessToken, baseURI, optOut, - "CLI Setup Started", + "CLI Setup Step Started", map[string]interface{}{ "step": step, }, From 0e9ae990e7aa37893c91044ff8dbe67024b6d15a Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Tue, 30 Apr 2024 11:38:00 -0700 Subject: [PATCH 4/7] pass in opt out --- cmd/quickstart.go | 1 + internal/quickstart/container.go | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/cmd/quickstart.go b/cmd/quickstart.go index 9e3dd2ef..aab4c43b 100644 --- a/cmd/quickstart.go +++ b/cmd/quickstart.go @@ -45,6 +45,7 @@ func runQuickStart( defer f.Close() _, err = tea.NewProgram(quickstart.NewContainerModel( + viper.GetBool(cliflags.AnalyticsOptOut), analyticsTracker, environmentsClient, flagsClient, diff --git a/internal/quickstart/container.go b/internal/quickstart/container.go index d64d9462..547fa836 100644 --- a/internal/quickstart/container.go +++ b/internal/quickstart/container.go @@ -8,9 +8,7 @@ import ( "github.com/charmbracelet/bubbles/spinner" tea "github.com/charmbracelet/bubbletea" "github.com/muesli/reflow/wordwrap" - "github.com/spf13/viper" - "ldcli/cmd/cliflags" "ldcli/internal/analytics" "ldcli/internal/environments" "ldcli/internal/flags" @@ -40,6 +38,7 @@ func (s step) String() string { type ContainerModel struct { accessToken string analyticsTracker analytics.Tracker + analyticsOptOut bool baseUri string currentModel tea.Model currentStep step @@ -56,6 +55,7 @@ type ContainerModel struct { } func NewContainerModel( + analyticsOptOut bool, analyticsTracker analytics.Tracker, environmentsClient environments.Client, flagsClient flags.Client, @@ -64,6 +64,8 @@ func NewContainerModel( ) tea.Model { return ContainerModel{ accessToken: accessToken, + analyticsOptOut: analyticsOptOut, + analyticsTracker: analyticsTracker, baseUri: baseUri, currentModel: NewCreateFlagModel(flagsClient, accessToken, baseUri), currentStep: 1, @@ -79,7 +81,7 @@ func (m ContainerModel) Init() tea.Cmd { m.analyticsTracker, m.accessToken, m.baseUri, - viper.GetBool(cliflags.AnalyticsOptOut), + m.analyticsOptOut, m.currentStep.String(), ) } @@ -181,7 +183,7 @@ func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.analyticsTracker, m.accessToken, m.baseUri, - viper.GetBool(cliflags.AnalyticsOptOut), + m.analyticsOptOut, m.currentStep.String(), )) } From e0e58d287f5124596a5536738e9aab5e1dfc8711 Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Tue, 30 Apr 2024 11:40:55 -0700 Subject: [PATCH 5/7] change string --- internal/quickstart/container.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/internal/quickstart/container.go b/internal/quickstart/container.go index 547fa836..2b437c51 100644 --- a/internal/quickstart/container.go +++ b/internal/quickstart/container.go @@ -30,7 +30,13 @@ const ( ) func (s step) String() string { - return [...]string{"_", "1 - feature flag name", "2 - sdk selection", "3 - sdk installation", "4 - flag toggle"}[s] + return []string{ + "_", + "1 - feature flag name", + "2 - sdk selection", + "3 - sdk installation", + "4 - flag toggle", + }[s] } // ContainerModel is a high level container model that controls the nested models where each From d8de3690b03e25a5fd3af2c6f12619806056940d Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Tue, 30 Apr 2024 13:48:05 -0700 Subject: [PATCH 6/7] renamed event funcs --- internal/analytics/client.go | 8 ++++---- internal/quickstart/container.go | 4 ++-- internal/quickstart/messages.go | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/analytics/client.go b/internal/analytics/client.go index 13d37ddf..4c2d33e2 100644 --- a/internal/analytics/client.go +++ b/internal/analytics/client.go @@ -24,7 +24,7 @@ type Tracker interface { optOut bool, outcome string, ) - SendSetupStartedEvent( + SendSetupStepStartedEvent( accessToken, baseURI string, optOut bool, @@ -134,7 +134,7 @@ func (c *Client) SendCommandCompletedEvent( } } -func (c *Client) SendSetupStartedEvent( +func (c *Client) SendSetupStepStartedEvent( accessToken, baseURI string, optOut bool, @@ -173,7 +173,7 @@ func (c *NoopClient) SendCommandCompletedEvent( ) { } -func (c *NoopClient) SendSetupStartedEvent( +func (c *NoopClient) SendSetupStepStartedEvent( accessToken, baseURI string, optOut bool, @@ -229,7 +229,7 @@ func (m *MockTracker) SendCommandCompletedEvent( ) } -func (m *MockTracker) SendSetupStartedEvent( +func (m *MockTracker) SendSetupStepStartedEvent( accessToken, baseURI string, optOut bool, diff --git a/internal/quickstart/container.go b/internal/quickstart/container.go index 2b437c51..1e6fefbd 100644 --- a/internal/quickstart/container.go +++ b/internal/quickstart/container.go @@ -83,7 +83,7 @@ func NewContainerModel( } func (m ContainerModel) Init() tea.Cmd { - return trackSetupStartedEvent( + return trackSetupStepStartedEvent( m.analyticsTracker, m.accessToken, m.baseUri, @@ -185,7 +185,7 @@ func (m ContainerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } if sendEvent { - cmd = tea.Batch(cmd, trackSetupStartedEvent( + cmd = tea.Batch(cmd, trackSetupStepStartedEvent( m.analyticsTracker, m.accessToken, m.baseUri, diff --git a/internal/quickstart/messages.go b/internal/quickstart/messages.go index c6ef6515..9b8bf2fd 100644 --- a/internal/quickstart/messages.go +++ b/internal/quickstart/messages.go @@ -244,9 +244,9 @@ func selectedSDK(index int) tea.Cmd { type eventTrackedMsg struct{} -func trackSetupStartedEvent(tracker analytics.Tracker, accessToken, baseURI string, optOut bool, step string) tea.Cmd { +func trackSetupStepStartedEvent(tracker analytics.Tracker, accessToken, baseURI string, optOut bool, step string) tea.Cmd { return func() tea.Msg { - tracker.SendSetupStartedEvent(accessToken, baseURI, optOut, step) + tracker.SendSetupStepStartedEvent(accessToken, baseURI, optOut, step) return eventTrackedMsg{} } From bdb6c67830a0f996430ac8e64be50df674dfb40c Mon Sep 17 00:00:00 2001 From: Sunny Guduru Date: Tue, 30 Apr 2024 13:50:33 -0700 Subject: [PATCH 7/7] alphabetize --- cmd/quickstart.go | 2 +- internal/quickstart/container.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/quickstart.go b/cmd/quickstart.go index aab4c43b..acac70a4 100644 --- a/cmd/quickstart.go +++ b/cmd/quickstart.go @@ -45,11 +45,11 @@ func runQuickStart( defer f.Close() _, err = tea.NewProgram(quickstart.NewContainerModel( - viper.GetBool(cliflags.AnalyticsOptOut), analyticsTracker, environmentsClient, flagsClient, viper.GetString(cliflags.AccessTokenFlag), + viper.GetBool(cliflags.AnalyticsOptOut), viper.GetString(cliflags.BaseURIFlag), )).Run() if err != nil { diff --git a/internal/quickstart/container.go b/internal/quickstart/container.go index 1e6fefbd..5f4b5729 100644 --- a/internal/quickstart/container.go +++ b/internal/quickstart/container.go @@ -43,8 +43,8 @@ func (s step) String() string { // represents a step in the quick-start flow. type ContainerModel struct { accessToken string - analyticsTracker analytics.Tracker analyticsOptOut bool + analyticsTracker analytics.Tracker baseUri string currentModel tea.Model currentStep step @@ -61,11 +61,11 @@ type ContainerModel struct { } func NewContainerModel( - analyticsOptOut bool, analyticsTracker analytics.Tracker, environmentsClient environments.Client, flagsClient flags.Client, accessToken string, + analyticsOptOut bool, baseUri string, ) tea.Model { return ContainerModel{