diff --git a/.golangci.yml b/.golangci.yml index 2108dfe..767595c 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -18,7 +18,8 @@ linters: issues: exclusions: rules: - - path: _test\.go + - path: ".*_test\\.go" linters: - errcheck - gocritic + - errorlint diff --git a/cmd/server/main.go b/cmd/server/main.go index 1d8e2d7..72be8a2 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "fmt" "log/slog" "net/http" "os" @@ -20,21 +21,25 @@ import ( func main() { slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))) + if err := run(); err != nil { + slog.Error("fatal error", "err", err) + os.Exit(1) + } +} +func run() error { cfg, err := config.Load() if err != nil { - slog.Error("config error", "err", err) - os.Exit(1) + return fmt.Errorf("config: %w", err) } ctx := context.Background() s, err := store.NewStore(ctx, cfg.MongoURI) if err != nil { - slog.Error("failed to connect to mongodb", "err", err) - os.Exit(1) + return fmt.Errorf("mongodb: %w", err) } - defer s.Close(ctx) + defer func() { _ = s.Close(ctx) }() castClient := cast.NewClient(cfg.CastAPIURL, cfg.CastAPIKey, cfg.CastSenderID) ghlAPI := ghl.NewAPIClient() @@ -42,8 +47,7 @@ func main() { webhookHandler, err := ghl.NewWebhookHandler(cfg.GHLWebhookPublicKey, castClient, ghlAPI, oauthHandler, s) if err != nil { - slog.Error("failed to initialize webhook handler", "err", err) - os.Exit(1) + return fmt.Errorf("webhook handler: %w", err) } r := chi.NewRouter() @@ -77,9 +81,9 @@ func main() { slog.Info("cast-ghl-provider started", "port", cfg.Port, "base_url", cfg.BaseURL) if err := srv.ListenAndServe(); err != http.ErrServerClosed { - slog.Error("server error", "err", err) - os.Exit(1) + return fmt.Errorf("server: %w", err) } + return nil } func healthCheck(w http.ResponseWriter, r *http.Request) { diff --git a/internal/cast/client.go b/internal/cast/client.go index e19b035..13194a2 100644 --- a/internal/cast/client.go +++ b/internal/cast/client.go @@ -60,7 +60,7 @@ func (c *Client) SendSMS(ctx context.Context, to, message string) (*SendResponse } } slog.Warn("cast api rate limited, retrying", "attempt", attempt+1, "wait", wait) - resp.Body.Close() + _ = resp.Body.Close() select { case <-ctx.Done(): return nil, ctx.Err() @@ -70,7 +70,7 @@ func (c *Client) SendSMS(ctx context.Context, to, message string) (*SendResponse } data, err := io.ReadAll(resp.Body) - resp.Body.Close() + _ = resp.Body.Close() if err != nil { return nil, err } diff --git a/internal/cast/client_test.go b/internal/cast/client_test.go index 81dd4e9..0181eab 100644 --- a/internal/cast/client_test.go +++ b/internal/cast/client_test.go @@ -3,6 +3,7 @@ package cast import ( "context" "encoding/json" + "errors" "net/http" "net/http/httptest" "sync/atomic" @@ -52,8 +53,8 @@ func TestSendSMS_APIError(t *testing.T) { if err == nil { t.Fatal("expected error, got nil") } - castErr, ok := err.(*CastAPIError) - if !ok { + var castErr *CastAPIError + if !errors.As(err, &castErr) { t.Fatalf("expected CastAPIError, got %T", err) } if castErr.StatusCode != http.StatusPaymentRequired { @@ -73,8 +74,8 @@ func TestSendSMS_SuccessFalseInBody(t *testing.T) { if err == nil { t.Fatal("expected error, got nil") } - castErr, ok := err.(*CastAPIError) - if !ok { + var castErr *CastAPIError + if !errors.As(err, &castErr) { t.Fatalf("expected CastAPIError, got %T", err) } if castErr.APIError != "invalid number" { @@ -133,8 +134,8 @@ func TestSendSMS_Unauthorized(t *testing.T) { if err == nil { t.Fatal("expected error for 401, got nil") } - castErr, ok := err.(*CastAPIError) - if !ok { + var castErr *CastAPIError + if !errors.As(err, &castErr) { t.Fatalf("expected CastAPIError, got %T: %v", err, err) } if castErr.StatusCode != http.StatusUnauthorized { diff --git a/internal/ghl/api.go b/internal/ghl/api.go index a710fa8..e0c4c23 100644 --- a/internal/ghl/api.go +++ b/internal/ghl/api.go @@ -44,7 +44,7 @@ func (c *APIClient) UpdateMessageStatus(ctx context.Context, accessToken, messag if err != nil { return err } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() respBody, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("ghl update status: failed to read response body: %w", err) @@ -75,7 +75,7 @@ func (c *APIClient) PostInboundMessage(ctx context.Context, accessToken string, if err != nil { return nil, err } - defer resp.Body.Close() + defer func() { _ = resp.Body.Close() }() respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, err