diff --git a/analytics/mocks/Repository.go b/analytics/mocks/Repository.go new file mode 100644 index 0000000..ebe1f83 --- /dev/null +++ b/analytics/mocks/Repository.go @@ -0,0 +1,68 @@ +// Code generated by mockery v2.10.4. DO NOT EDIT. + +package mocks + +import mock "github.com/stretchr/testify/mock" + +// Repository is an autogenerated mock type for the Repository type +type Repository struct { + mock.Mock +} + +// Get provides a mock function with given fields: key +func (_m *Repository) Get(key string) string { + ret := _m.Called(key) + + var r0 string + if rf, ok := ret.Get(0).(func(string) string); ok { + r0 = rf(key) + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// List provides a mock function with given fields: +func (_m *Repository) List() []string { + ret := _m.Called() + + var r0 []string + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + return r0 +} + +// Set provides a mock function with given fields: key, value +func (_m *Repository) Set(key string, value string) error { + ret := _m.Called(key, value) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string) error); ok { + r0 = rf(key, value) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// Unset provides a mock function with given fields: key +func (_m *Repository) Unset(key string) error { + ret := _m.Called(key) + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(key) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/analytics/mocks/TrackerFactory.go b/analytics/mocks/TrackerFactory.go new file mode 100644 index 0000000..17ee797 --- /dev/null +++ b/analytics/mocks/TrackerFactory.go @@ -0,0 +1,35 @@ +// Code generated by mockery v2.10.4. DO NOT EDIT. + +package mocks + +import ( + analytics "github.com/bitrise-io/go-utils/v2/analytics" + mock "github.com/stretchr/testify/mock" +) + +// TrackerFactory is an autogenerated mock type for the TrackerFactory type +type TrackerFactory struct { + mock.Mock +} + +// Execute provides a mock function with given fields: _a0 +func (_m *TrackerFactory) Execute(_a0 ...analytics.Properties) analytics.Tracker { + _va := make([]interface{}, len(_a0)) + for _i := range _a0 { + _va[_i] = _a0[_i] + } + var _ca []interface{} + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 analytics.Tracker + if rf, ok := ret.Get(0).(func(...analytics.Properties) analytics.Tracker); ok { + r0 = rf(_a0...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(analytics.Tracker) + } + } + + return r0 +} diff --git a/analytics/track.go b/analytics/track.go new file mode 100644 index 0000000..f16894d --- /dev/null +++ b/analytics/track.go @@ -0,0 +1,30 @@ +package analytics + +import ( + "fmt" + + "github.com/bitrise-io/go-utils/v2/analytics" + "github.com/bitrise-io/go-utils/v2/env" +) + +// TrackerFactory ... +type TrackerFactory func(...analytics.Properties) analytics.Tracker + +const ( + stepExecutionIDEnvKey = "BITRISE_STEP_EXECUTION_ID" + stepExecutionID = "step_execution_id" +) + +// NewStepTracker creates a tracker that adds the `step_execution_id` property to all events logged with this instance. This is useful for joining the logged data with other tables on the execution ID. +func NewStepTracker(repository env.Repository, trackerFactory TrackerFactory) (analytics.Tracker, error) { + id := repository.Get(stepExecutionIDEnvKey) + if id == "" { + return nil, fmt.Errorf("no step execution ID found") + } + return trackerFactory(analytics.Properties{stepExecutionID: id}), nil +} + +// NewDefaultStepTracker ... +func NewDefaultStepTracker(repository env.Repository) (analytics.Tracker, error) { + return NewStepTracker(repository, analytics.NewDefaultTracker) +} diff --git a/analytics/track_test.go b/analytics/track_test.go new file mode 100644 index 0000000..fe87560 --- /dev/null +++ b/analytics/track_test.go @@ -0,0 +1,29 @@ +package analytics + +import ( + "testing" + + "github.com/bitrise-io/go-steputils/v2/analytics/mocks" + "github.com/bitrise-io/go-utils/v2/analytics" +) + +func TestNewStepTrackerFailsIfStepExecutionIDIsNotFound(t *testing.T) { + repository := new(mocks.Repository) + repository.On("Get", "BITRISE_STEP_EXECUTION_ID").Return("") + _, err := NewDefaultStepTracker(repository) + if err == nil { + t.Error("Expected error, got nil") + } +} + +func TestNewStepTrackerAddsStepExecutionIDToNewTracker(t *testing.T) { + repository := new(mocks.Repository) + repository.On("Get", "BITRISE_STEP_EXECUTION_ID").Return("123") + factory := new(mocks.TrackerFactory) + factory.On("Execute", analytics.Properties{"step_execution_id": "123"}).Return(nil, nil) + _, err := NewStepTracker(repository, factory.Execute) + if err != nil { + t.Errorf("Expected no error, got %s", err) + } + factory.AssertExpectations(t) +} diff --git a/go.sum b/go.sum index 52e2075..be5f69b 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= @@ -28,8 +29,9 @@ github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=