-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
183 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright (c) 2023 Gitpod GmbH. All rights reserved. | ||
// Licensed under the GNU Affero General Public License (AGPL). | ||
// See License.AGPL.txt in the project root for license information. | ||
|
||
package cmd | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"testing" | ||
|
||
"github.com/bufbuild/connect-go" | ||
v1 "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1" | ||
gitpod_experimental_v1connect "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1/v1connect" | ||
"github.com/gitpod-io/local-app/pkg/config" | ||
) | ||
|
||
func TestLoginCmd(t *testing.T) { | ||
RunCommandTests(t, []CommandTest{ | ||
{ | ||
Name: "test unauthenticated", | ||
Commandline: []string{"login", "--token", "foo"}, | ||
Config: &config.Config{ | ||
ActiveContext: "test", | ||
}, | ||
PrepServer: func(mux *http.ServeMux) { | ||
mux.Handle(gitpod_experimental_v1connect.NewTeamsServiceHandler(&testLoginCmdSrv{ | ||
Err: connect.NewError(connect.CodeUnauthenticated, fmt.Errorf("unauthenticated")), | ||
})) | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
type testLoginCmdSrv struct { | ||
Err error | ||
gitpod_experimental_v1connect.UnimplementedTeamsServiceHandler | ||
} | ||
|
||
func (srv testLoginCmdSrv) ListTeams(context.Context, *connect.Request[v1.ListTeamsRequest]) (*connect.Response[v1.ListTeamsResponse], error) { | ||
return nil, srv.Err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// Copyright (c) 2022 Gitpod GmbH. All rights reserved. | ||
// Licensed under the GNU Affero General Public License (AGPL). | ||
// See License-AGPL.txt in the project root for license information. | ||
|
||
package telemetry | ||
|
||
import ( | ||
"errors" | ||
"log/slog" | ||
"math/rand" | ||
"os" | ||
"runtime" | ||
"strings" | ||
"time" | ||
|
||
"github.com/gitpod-io/local-app/pkg/prettyprint" | ||
segment "github.com/segmentio/analytics-go/v3" | ||
"github.com/spf13/cobra" | ||
"golang.org/x/exp/slices" | ||
) | ||
|
||
// Injected at build time | ||
var segmentKey = "TgiJIVvFsBGwmxbnnt5NeeDaian9nr3n" | ||
|
||
var opts struct { | ||
Enabled bool | ||
Identity string | ||
Version string | ||
|
||
client segment.Client | ||
} | ||
|
||
// Init initialises the telemetry | ||
func Init(enabled bool, identity, version string) { | ||
opts.Enabled = enabled | ||
if !enabled { | ||
return | ||
} | ||
|
||
opts.Version = version | ||
opts.Identity = identity | ||
|
||
if segmentKey != "" { | ||
opts.client = segment.New(segmentKey) | ||
} | ||
} | ||
|
||
// DoNotTrack returns true if the user opted out of telemetry | ||
// Implements the https://consoledonottrack.com/ proposal. | ||
func DoNotTrack() bool { | ||
return os.Getenv("DO_NOT_TRACK") == "1" | ||
} | ||
|
||
// RandomIdentity generates a random identity | ||
func RandomIdentity() string { | ||
letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890") | ||
b := make([]rune, 32) | ||
for i := range b { | ||
b[i] = letters[rand.Intn(len(letters))] | ||
} | ||
return string(b) | ||
} | ||
|
||
func Close() { | ||
if opts.client != nil { | ||
opts.client.Close() | ||
} | ||
} | ||
|
||
// Identity returns the identity | ||
func Identity() string { | ||
return opts.Identity | ||
} | ||
|
||
// Enabled returns true if the telemetry is enabled | ||
func Enabled() bool { | ||
return opts.Enabled && opts.Identity != "" && opts.client != nil | ||
} | ||
|
||
func track(event string, props segment.Properties) { | ||
if !Enabled() { | ||
return | ||
} | ||
slog.Debug("tracking telemetry", "props", props, "event", event) | ||
|
||
err := opts.client.Enqueue(segment.Track{ | ||
AnonymousId: opts.Identity, | ||
Event: event, | ||
Timestamp: time.Now(), | ||
Properties: props, | ||
}) | ||
if err != nil { | ||
slog.Debug("failed to track telemetry", "err", err) | ||
} | ||
} | ||
|
||
// RecordCommand records the execution of a CLI command | ||
func RecordCommand(cmd *cobra.Command) { | ||
var command []string | ||
for c := cmd; c != nil; c = c.Parent() { | ||
command = append(command, c.Name()) | ||
} | ||
slices.Reverse(command) | ||
|
||
track("gitpodcli_command", defaultProperties(). | ||
Set("command", strings.Join(command, " "))) | ||
} | ||
|
||
// RecordError records an exception that occurred | ||
func RecordError(err error) { | ||
var exception *prettyprint.ErrSystemException | ||
if !errors.As(err, &exception) { | ||
return | ||
} | ||
|
||
track("gitpodcli_exception", defaultProperties(). | ||
Set("context", exception.Context). | ||
Set("error", exception.Err.Error())) | ||
} | ||
|
||
func defaultProperties() segment.Properties { | ||
return segment.NewProperties(). | ||
Set("goos", runtime.GOOS). | ||
Set("goarch", runtime.GOARCH). | ||
Set("version", opts.Version) | ||
} |