Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inject logger using context #1116

Merged
merged 1 commit into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions cmd/api/api.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package api

import (
"context"
"fmt"
"strings"

Expand All @@ -13,31 +14,33 @@

// NewClient initializes a new api client with all options following the
// passed in parameters.
func NewClient(params paramscmd.API) (*api.Client, error) {
func NewClient(ctx context.Context, params paramscmd.API) (*api.Client, error) {
withAuth, err := api.WithAuth(api.BasicAuth{
Secret: params.Key,
})
if err != nil {
return nil, fmt.Errorf("failed to set up auth option on api client: %w", err)
}

return newClient(params, withAuth)
return newClient(ctx, params, withAuth)
}

// NewClientWithoutAuth initializes a new api client with all options following the
// passed in parameters and disabled authentication.
func NewClientWithoutAuth(params paramscmd.API) (*api.Client, error) {
return newClient(params)
func NewClientWithoutAuth(ctx context.Context, params paramscmd.API) (*api.Client, error) {
return newClient(ctx, params)
}

// newClient contains the logic of client initialization, except auth initialization.
func newClient(params paramscmd.API, opts ...api.Option) (*api.Client, error) {
func newClient(ctx context.Context, params paramscmd.API, opts ...api.Option) (*api.Client, error) {
opts = append(opts, api.WithTimeout(params.Timeout))
opts = append(opts, api.WithHostname(strings.TrimSpace(params.Hostname)))

logger := log.Extract(ctx)

tz, err := timezone()
if err != nil {
log.Debugf("failed to detect local timezone: %s", err)
logger.Debugf("failed to detect local timezone: %s", err)

Check warning on line 43 in cmd/api/api.go

View check run for this annotation

Codecov / codecov/patch

cmd/api/api.go#L43

Added line #L43 was not covered by tests
} else {
opts = append(opts, api.WithTimezone(strings.TrimSpace(tz)))
}
Expand All @@ -54,7 +57,7 @@

opts = append(opts, withSSLCert)
} else if !params.DisableSSLVerify {
opts = append(opts, api.WithSSLCertPool(api.CACerts()))
opts = append(opts, api.WithSSLCertPool(api.CACerts(ctx)))
}

if params.ProxyURL != "" {
Expand All @@ -66,7 +69,7 @@
opts = append(opts, withProxy)

if strings.Contains(params.ProxyURL, `\\`) {
withNTLMRetry, err := api.WithNTLMRequestRetry(params.ProxyURL)
withNTLMRetry, err := api.WithNTLMRequestRetry(ctx, params.ProxyURL)

Check warning on line 72 in cmd/api/api.go

View check run for this annotation

Codecov / codecov/patch

cmd/api/api.go#L72

Added line #L72 was not covered by tests
if err != nil {
return nil, fmt.Errorf("failed to set up ntlm request retry option on api client: %w", err)
}
Expand All @@ -75,7 +78,7 @@
}
}

opts = append(opts, api.WithUserAgent(params.Plugin))
opts = append(opts, api.WithUserAgent(ctx, params.Plugin))

return api.NewClient(params.URL, opts...), nil
}
Expand Down
3 changes: 2 additions & 1 deletion cmd/configread/configread.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package configread

import (
"context"
"errors"
"fmt"
"strings"
Expand All @@ -18,9 +19,9 @@
}

// Run prints the value for the given config key.
func Run(v *viper.Viper) (int, error) {
func Run(_ context.Context, v *viper.Viper) (int, error) {
output, err := Read(v)
if err != nil {

Check warning on line 24 in cmd/configread/configread.go

View check run for this annotation

Codecov / codecov/patch

cmd/configread/configread.go#L22-L24

Added lines #L22 - L24 were not covered by tests
return exitcode.ErrConfigFileRead, fmt.Errorf(
"failed to read in config: %s",
err,
Expand Down
11 changes: 6 additions & 5 deletions cmd/configwrite/configwrite.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package configwrite

import (
"context"
"errors"
"fmt"
"strings"
Expand All @@ -19,16 +20,16 @@
}

// Run loads wakatime config file and call Write().
func Run(v *viper.Viper) (int, error) {
w, err := ini.NewWriter(v, ini.FilePath)
func Run(ctx context.Context, v *viper.Viper) (int, error) {
w, err := ini.NewWriter(ctx, v, ini.FilePath)
if err != nil {
return exitcode.ErrConfigFileParse, fmt.Errorf(
"failed to parse config file: %s",
err,
)
}

if err := Write(v, w); err != nil {
if err := Write(ctx, v, w); err != nil {

Check warning on line 32 in cmd/configwrite/configwrite.go

View check run for this annotation

Codecov / codecov/patch

cmd/configwrite/configwrite.go#L32

Added line #L32 was not covered by tests
return exitcode.ErrGeneric, fmt.Errorf(
"failed to write to config file: %s",
err,
Expand All @@ -39,13 +40,13 @@
}

// Write writes value(s) to given config key(s) and persist on disk.
func Write(v *viper.Viper, w ini.Writer) error {
func Write(ctx context.Context, v *viper.Viper, w ini.Writer) error {
params, err := LoadParams(v)
if err != nil {
return fmt.Errorf("failed to load command parameters: %w", err)
}

return w.Write(params.Section, params.KeyValue)
return w.Write(ctx, params.Section, params.KeyValue)
}

// LoadParams loads needed data from the configuration file.
Expand Down
19 changes: 11 additions & 8 deletions cmd/configwrite/configwrite_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package configwrite_test

import (
"context"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -72,8 +73,10 @@ func TestWrite(t *testing.T) {

defer tmpFile.Close()

ctx := context.Background()

v := viper.New()
ini, err := ini.NewWriter(v, func(vp *viper.Viper) (string, error) {
ini, err := ini.NewWriter(ctx, v, func(_ context.Context, vp *viper.Viper) (string, error) {
assert.Equal(t, v, vp)
return tmpFile.Name(), nil
})
Expand All @@ -82,7 +85,7 @@ func TestWrite(t *testing.T) {
v.Set("config-section", "settings")
v.Set("config-write", map[string]string{"debug": "false"})

err = configwrite.Write(v, ini)
err = configwrite.Write(ctx, v, ini)
require.NoError(t, err)

err = ini.File.Reload()
Expand Down Expand Up @@ -117,7 +120,7 @@ func TestWriteErr(t *testing.T) {
v.Set("config-section", test.Section)
v.Set("config-write", test.Value)

err := configwrite.Write(v, w)
err := configwrite.Write(context.Background(), v, w)
require.Error(t, err)

assert.Equal(
Expand All @@ -133,7 +136,7 @@ func TestWriteErr(t *testing.T) {
func TestWriteSaveErr(t *testing.T) {
v := viper.New()
w := &mockWriter{
WriteFn: func(section string, keyValue map[string]string) error {
WriteFn: func(_ context.Context, section string, keyValue map[string]string) error {
assert.Equal(t, "settings", section)
assert.Equal(t, map[string]string{"debug": "false"}, keyValue)

Expand All @@ -144,14 +147,14 @@ func TestWriteSaveErr(t *testing.T) {
v.Set("config-section", "settings")
v.Set("config-write", map[string]string{"debug": "false"})

err := configwrite.Write(v, w)
err := configwrite.Write(context.Background(), v, w)
assert.Error(t, err)
}

type mockWriter struct {
WriteFn func(section string, keyValue map[string]string) error
WriteFn func(ctx context.Context, section string, keyValue map[string]string) error
}

func (m *mockWriter) Write(section string, keyValue map[string]string) error {
return m.WriteFn(section, keyValue)
func (m *mockWriter) Write(ctx context.Context, section string, keyValue map[string]string) error {
return m.WriteFn(ctx, section, keyValue)
}
23 changes: 13 additions & 10 deletions cmd/fileexperts/fileexperts.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fileexperts

import (
"context"
"fmt"

apicmd "github.com/wakatime/wakatime-cli/cmd/api"
Expand All @@ -18,8 +19,8 @@
)

// Run executes the file-experts command.
func Run(v *viper.Viper) (int, error) {
output, err := FileExperts(v)
func Run(ctx context.Context, v *viper.Viper) (int, error) {
output, err := FileExperts(ctx, v)

Check warning on line 23 in cmd/fileexperts/fileexperts.go

View check run for this annotation

Codecov / codecov/patch

cmd/fileexperts/fileexperts.go#L22-L23

Added lines #L22 - L23 were not covered by tests
if err != nil {
if errwaka, ok := err.(wakaerror.Error); ok {
return errwaka.ExitCode(), fmt.Errorf("file experts fetch failed: %s", errwaka.Message())
Expand All @@ -31,29 +32,31 @@
)
}

log.Debugln("successfully fetched file experts")
logger := log.Extract(ctx)
logger.Debugln("successfully fetched file experts")

Check warning on line 37 in cmd/fileexperts/fileexperts.go

View check run for this annotation

Codecov / codecov/patch

cmd/fileexperts/fileexperts.go#L35-L37

Added lines #L35 - L37 were not covered by tests
fmt.Println(output)

return exitcode.Success, nil
}

// FileExperts returns a rendered file experts of todays coding activity.
func FileExperts(v *viper.Viper) (string, error) {
params, err := LoadParams(v)
func FileExperts(ctx context.Context, v *viper.Viper) (string, error) {
params, err := LoadParams(ctx, v)
if err != nil {
return "", fmt.Errorf("failed to load command parameters: %w", err)
}

handleOpts := initHandleOptions(params)

apiClient, err := apicmd.NewClientWithoutAuth(params.API)
apiClient, err := apicmd.NewClientWithoutAuth(ctx, params.API)
if err != nil {
return "", fmt.Errorf("failed to initialize api client: %w", err)
}

handle := fileexperts.NewHandle(apiClient, handleOpts...)

results, err := handle([]heartbeat.Heartbeat{{Entity: params.Heartbeat.Entity}})
results, err := handle(ctx, []heartbeat.Heartbeat{{Entity: params.Heartbeat.Entity}})
if err != nil {
return "", err
}
Expand All @@ -75,17 +78,17 @@

// LoadParams loads file-expert config params from viper.Viper instance. Returns ErrAuth
// if failed to retrieve api key.
func LoadParams(v *viper.Viper) (paramscmd.Params, error) {
func LoadParams(ctx context.Context, v *viper.Viper) (paramscmd.Params, error) {
if v == nil {
return paramscmd.Params{}, fmt.Errorf("viper instance unset")
}

heartbeatParams, err := paramscmd.LoadHeartbeatParams(v)
heartbeatParams, err := paramscmd.LoadHeartbeatParams(ctx, v)
if err != nil {
return paramscmd.Params{}, fmt.Errorf("failed to load heartbeat params: %s", err)
}

apiParams, err := paramscmd.LoadAPIParams(v)
apiParams, err := paramscmd.LoadAPIParams(ctx, v)
if err != nil {
return paramscmd.Params{}, fmt.Errorf("failed to load API parameters: %w", err)
}
Expand Down
39 changes: 17 additions & 22 deletions cmd/fileexperts/fileexperts_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fileexperts_test

import (
"context"
"encoding/json"
"fmt"
"io"
Expand Down Expand Up @@ -86,9 +87,8 @@ func TestFileExperts(t *testing.T) {
v.Set("plugin", plugin)
v.Set("project", "wakatime-cli")
v.Set("entity", "testdata/main.go")
v.Set("file-experts", true)

output, err := fileexperts.FileExperts(v)
output, err := fileexperts.FileExperts(context.Background(), v)
require.NoError(t, err)

assert.Equal(t, "You: 40 mins | Karl: 21 mins", output)
Expand All @@ -97,33 +97,31 @@ func TestFileExperts(t *testing.T) {
}

func TestFileExperts_NonExistingEntity(t *testing.T) {
tmpDir := t.TempDir()
ctx := context.Background()

logFile, err := os.CreateTemp(tmpDir, "")
logFile, err := os.CreateTemp(t.TempDir(), "")
require.NoError(t, err)

defer logFile.Close()

v := viper.New()
v.Set("key", "00000000-0000-4000-8000-000000000000")
v.Set("api-url", "https://example.org")
v.Set("entity", "nonexisting")
v.Set("file-experts", true)
v.Set("key", "00000000-0000-4000-8000-000000000000")
v.Set("log-file", logFile.Name())
v.Set("verbose", true)

cmd.SetupLogging(v)
logger, err := cmd.SetupLogging(ctx, v)
require.NoError(t, err)

defer func() {
if file, ok := log.Output().(*os.File); ok {
_ = file.Sync()
file.Close()
} else if handler, ok := log.Output().(io.Closer); ok {
handler.Close()
}
}()
defer logger.Flush()

ctx = log.ToContext(ctx, logger)

_, err = fileexperts.FileExperts(ctx, v)
require.NoError(t, err)

_, err = fileexperts.FileExperts(v)
err = logFile.Sync()
require.NoError(t, err)

output, err := io.ReadAll(logFile)
Expand All @@ -148,9 +146,8 @@ func TestFileExperts_ErrApi(t *testing.T) {
v.Set("key", "00000000-0000-4000-8000-000000000000")
v.Set("api-url", testServerURL)
v.Set("entity", "testdata/main.go")
v.Set("file-experts", true)

_, err := fileexperts.FileExperts(v)
_, err := fileexperts.FileExperts(context.Background(), v)
require.Error(t, err)

var errapi api.Err
Expand Down Expand Up @@ -183,9 +180,8 @@ func TestFileExperts_ErrAuth(t *testing.T) {
v.Set("key", "00000000-0000-4000-8000-000000000000")
v.Set("api-url", testServerURL)
v.Set("entity", "testdata/main.go")
v.Set("file-experts", true)

_, err := fileexperts.FileExperts(v)
_, err := fileexperts.FileExperts(context.Background(), v)
require.Error(t, err)

var errauth api.ErrAuth
Expand Down Expand Up @@ -217,9 +213,8 @@ func TestFileExperts_ErrBadRequest(t *testing.T) {
v.Set("key", "00000000-0000-4000-8000-000000000000")
v.Set("api-url", testServerURL)
v.Set("entity", "testdata/main.go")
v.Set("file-experts", true)

_, err := fileexperts.FileExperts(v)
_, err := fileexperts.FileExperts(context.Background(), v)
require.Error(t, err)

var errbadRequest api.ErrBadRequest
Expand Down
Loading
Loading