3
3
package root
4
4
5
5
import (
6
+ "context"
7
+ "errors"
8
+ "fmt"
9
+ "io"
10
+ "net"
11
+ "os"
12
+ "strings"
13
+
14
+ "github.com/AlecAivazis/survey/v2/terminal"
6
15
"github.com/MakeNowJust/heredoc"
7
16
"github.com/spf13/cobra"
8
17
9
18
"github.com/algolia/cli/pkg/cmd/apikey"
10
19
"github.com/algolia/cli/pkg/cmd/application"
20
+ "github.com/algolia/cli/pkg/cmd/factory"
11
21
"github.com/algolia/cli/pkg/cmd/index"
12
22
"github.com/algolia/cli/pkg/cmd/objects"
13
23
"github.com/algolia/cli/pkg/cmd/open"
@@ -16,9 +26,20 @@ import (
16
26
"github.com/algolia/cli/pkg/cmd/settings"
17
27
"github.com/algolia/cli/pkg/cmd/synonyms"
18
28
"github.com/algolia/cli/pkg/cmdutil"
29
+ "github.com/algolia/cli/pkg/config"
30
+ "github.com/algolia/cli/pkg/telemetry"
19
31
"github.com/algolia/cli/pkg/version"
20
32
)
21
33
34
+ type exitCode int
35
+
36
+ const (
37
+ exitOK exitCode = 0
38
+ exitError exitCode = 1
39
+ exitCancel exitCode = 2
40
+ exitAuth exitCode = 4
41
+ )
42
+
22
43
func NewRootCmd (f * cmdutil.Factory ) * cobra.Command {
23
44
cmd := & cobra.Command {
24
45
Use : "algolia <command> <subcommand> [flags]" ,
@@ -73,3 +94,146 @@ func NewRootCmd(f *cmdutil.Factory) *cobra.Command {
73
94
74
95
return cmd
75
96
}
97
+
98
+ func Execute () exitCode {
99
+ hasDebug := os .Getenv ("DEBUG" ) != ""
100
+ hasTelemetry := os .Getenv ("ALGOLIA_CLI_TELEMETRY" ) != "0"
101
+ fmt .Println ("hasDebug:" , hasDebug )
102
+ fmt .Println ("hasTelemetry:" , hasTelemetry )
103
+
104
+ // Set up the command factory.
105
+ cfg := config.Config {}
106
+ cfg .InitConfig ()
107
+ cmdFactory := factory .New (& cfg )
108
+ stderr := cmdFactory .IOStreams .ErrOut
109
+
110
+ // Set up the root command.
111
+ rootCmd := NewRootCmd (cmdFactory )
112
+
113
+ // Pre-command auth check and telemetry setup.
114
+ authError := errors .New ("authError" )
115
+ rootCmd .PersistentPreRunE = func (cmd * cobra.Command , args []string ) error {
116
+ if cmdutil .IsAuthCheckEnabled (cmd ) {
117
+ if err := cmdutil .CheckAuth (cfg ); err != nil {
118
+ fmt .Fprintf (stderr , "Authentication error: %s\n " , err )
119
+ fmt .Fprintln (stderr , "Please run `algolia application add` to configure your first application." )
120
+ return authError
121
+ }
122
+ }
123
+
124
+ // Initialize telemetry context.
125
+ appID , err := cfg .Application .GetID ()
126
+ if err != nil {
127
+ appID = ""
128
+ }
129
+ telemetryMetadata := telemetry .GetEventMetadata (cmd .Context ())
130
+ telemetryMetadata .SetCobraCommandContext (cmd )
131
+ telemetryMetadata .SetAppID (appID )
132
+ telemetryMetadata .SetConfiguredApplicationsNb (len (cfg .ConfiguredApplications ()))
133
+
134
+ ctx := cmd .Context ()
135
+ telemetryClient := telemetry .GetTelemetryClient (ctx )
136
+
137
+ // Identify the user.
138
+ err = telemetryClient .Identify (ctx )
139
+ if err != nil && hasDebug {
140
+ fmt .Fprintf (stderr , "Failed to identify user: %s\n " , err )
141
+ return err
142
+ }
143
+
144
+ // Send telemetry.
145
+ err = telemetryClient .Track (ctx , "Command Invoked" )
146
+ if err != nil && hasDebug {
147
+ fmt .Fprintf (stderr , "Error tracking telemetry: %s\n " , err )
148
+ }
149
+
150
+ return nil
151
+ }
152
+
153
+ // Command context is used to pass information to the telemetry client.
154
+ ctx , err := createContext (rootCmd , stderr , hasDebug , hasTelemetry )
155
+ if err != nil {
156
+ printError (stderr , err , rootCmd , hasDebug )
157
+ return exitError
158
+ }
159
+
160
+ // Run the command.
161
+ cmd , err := rootCmd .ExecuteContextC (ctx )
162
+
163
+ // Post-command telemetry
164
+ ctx = cmd .Context ()
165
+ telemetryClient := telemetry .GetTelemetryClient (ctx )
166
+ telemetryErr := telemetryClient .Track (ctx , "Command Finished" )
167
+ if telemetryErr != nil && hasDebug {
168
+ fmt .Fprintf (stderr , "Error tracking telemetry: %s\n " , err )
169
+ }
170
+ telemetryErr = telemetryClient .Close () // flush telemetry events
171
+ if telemetryErr != nil && hasDebug {
172
+ fmt .Fprintf (stderr , "Error closing telemetry client: %s\n " , err )
173
+ }
174
+
175
+ // Handle eventual errors.
176
+ if err != nil {
177
+ if err == cmdutil .ErrSilent {
178
+ return exitError
179
+ } else if cmdutil .IsUserCancellation (err ) {
180
+ if errors .Is (err , terminal .InterruptErr ) {
181
+ // ensure the next shell prompt will start on its own line
182
+ fmt .Fprint (stderr , "\n " )
183
+ }
184
+ return exitCancel
185
+ } else if errors .Is (err , authError ) {
186
+ return exitAuth
187
+ }
188
+
189
+ printError (stderr , err , cmd , hasDebug )
190
+ return exitError
191
+ }
192
+
193
+ return exitOK
194
+ }
195
+
196
+ // createContext creates a context with telemetry.
197
+ func createContext (cmd * cobra.Command , stderr io.Writer , hasTelemetry bool , hasDebug bool ) (context.Context , error ) {
198
+ ctx := context .Background ()
199
+ telemetryMetadata := telemetry .NewEventMetadata ()
200
+ updatedCtx := telemetry .WithEventMetadata (ctx , telemetryMetadata )
201
+
202
+ var telemetryClient telemetry.TelemetryClient
203
+ var err error
204
+ if hasTelemetry {
205
+ telemetryClient , err = telemetry .NewAnalyticsTelemetryClient ()
206
+ // Fail silently if telemetry is not available unless in debug mode.
207
+ if err != nil && hasDebug {
208
+ fmt .Fprintf (stderr , "Error creating telemetry client: %s\n " , err )
209
+ return nil , err
210
+ }
211
+ } else {
212
+ telemetryClient = & telemetry.NoOpTelemetryClient {}
213
+ }
214
+ contextWithTelemetry := telemetry .WithTelemetryClient (updatedCtx , telemetryClient )
215
+ return contextWithTelemetry , nil
216
+ }
217
+
218
+ // printError prints an error to the stderr, with additional information if applicable.
219
+ func printError (out io.Writer , err error , cmd * cobra.Command , debug bool ) {
220
+ var dnsError * net.DNSError
221
+ if errors .As (err , & dnsError ) {
222
+ fmt .Fprintf (out , "error connecting to %s\n " , dnsError .Name )
223
+ if debug {
224
+ fmt .Fprintln (out , dnsError )
225
+ }
226
+ fmt .Fprintln (out , "check your internet connection or https://status.algolia.com" )
227
+ return
228
+ }
229
+
230
+ fmt .Fprintln (out , err )
231
+
232
+ var flagError * cmdutil.FlagError
233
+ if errors .As (err , & flagError ) || strings .HasPrefix (err .Error (), "unknown command " ) {
234
+ if ! strings .HasSuffix (err .Error (), "\n " ) {
235
+ fmt .Fprintln (out )
236
+ }
237
+ fmt .Fprintln (out , cmd .UsageString ())
238
+ }
239
+ }
0 commit comments