summaryrefslogtreecommitdiff
path: root/internal/api
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-01-25 20:55:58 -1000
committerPeter Stone <thepeterstone@gmail.com>2026-01-25 20:55:58 -1000
commitf5b997bfc4c77ef262726d14b30d387eb7acd1c6 (patch)
tree740879da10f3ddcd62bf276cd0632134b53a23c8 /internal/api
parentfa95c71494458070b78270e3d9170076028fc974 (diff)
Fix all static analysis errors (golangci-lint)
- Fix errcheck: handle all error return values in production code - Fix errcheck: handle all error return values in test files - Fix staticcheck: replace deprecated WithCredentialsFile with WithAuthCredentialsFile - Remove unused code: authHeaders, planToEatPlannerItem, planToEatResponse - Use defer func() { _ = x.Close() }() pattern for ignored close errors Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'internal/api')
-rw-r--r--internal/api/google_calendar.go3
-rw-r--r--internal/api/http.go4
-rw-r--r--internal/api/plantoeat.go25
-rw-r--r--internal/api/research_test.go18
-rw-r--r--internal/api/todoist_test.go12
-rw-r--r--internal/api/trello_test.go10
6 files changed, 26 insertions, 46 deletions
diff --git a/internal/api/google_calendar.go b/internal/api/google_calendar.go
index dc61f3d..e4f9c2f 100644
--- a/internal/api/google_calendar.go
+++ b/internal/api/google_calendar.go
@@ -55,7 +55,8 @@ func deduplicateEvents(events []models.CalendarEvent) []models.CalendarEvent {
// NewGoogleCalendarClient creates a client that fetches from multiple calendars.
// calendarIDs can be comma-separated (e.g., "cal1@group.calendar.google.com,cal2@group.calendar.google.com")
func NewGoogleCalendarClient(ctx context.Context, credentialsFile, calendarIDs string) (*GoogleCalendarClient, error) {
- srv, err := calendar.NewService(ctx, option.WithCredentialsFile(credentialsFile))
+ // Use type-safe credential loading (replaces deprecated WithCredentialsFile)
+ srv, err := calendar.NewService(ctx, option.WithAuthCredentialsFile(option.ServiceAccount, credentialsFile))
if err != nil {
return nil, fmt.Errorf("unable to retrieve Calendar client: %v", err)
}
diff --git a/internal/api/http.go b/internal/api/http.go
index 8854625..df28c65 100644
--- a/internal/api/http.go
+++ b/internal/api/http.go
@@ -95,7 +95,7 @@ func (c *BaseClient) PostEmpty(ctx context.Context, path string, headers map[str
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
- defer resp.Body.Close()
+ defer func() { _ = resp.Body.Close() }()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
body, _ := io.ReadAll(resp.Body)
@@ -126,7 +126,7 @@ func (c *BaseClient) doJSON(req *http.Request, result interface{}) error {
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
- defer resp.Body.Close()
+ defer func() { _ = resp.Body.Close() }()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
body, _ := io.ReadAll(resp.Body)
diff --git a/internal/api/plantoeat.go b/internal/api/plantoeat.go
index a7fdf58..5c24cc1 100644
--- a/internal/api/plantoeat.go
+++ b/internal/api/plantoeat.go
@@ -39,27 +39,6 @@ func (c *PlanToEatClient) SetSessionCookie(cookie string) {
c.sessionCookie = cookie
}
-func (c *PlanToEatClient) authHeaders() map[string]string {
- return map[string]string{"Authorization": "Bearer " + c.apiKey}
-}
-
-// planToEatPlannerItem represents a planner item from the API
-type planToEatPlannerItem struct {
- ID int `json:"id"`
- Date string `json:"date"`
- MealType string `json:"meal_type"`
- Recipe struct {
- ID int `json:"id"`
- Title string `json:"title"`
- URL string `json:"url"`
- } `json:"recipe"`
-}
-
-// planToEatResponse wraps the API response
-type planToEatResponse struct {
- Items []planToEatPlannerItem `json:"items"`
-}
-
// GetUpcomingMeals fetches meals by scraping the planner web interface
// Requires a valid session cookie set via SetSessionCookie
func (c *PlanToEatClient) GetUpcomingMeals(ctx context.Context, days int) ([]models.Meal, error) {
@@ -84,7 +63,7 @@ func (c *PlanToEatClient) GetUpcomingMeals(ctx context.Context, days int) ([]mod
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
- defer resp.Body.Close()
+ defer func() { _ = resp.Body.Close() }()
log.Printf("DEBUG [PlanToEat/Meals]: Response status %d", resp.StatusCode)
@@ -238,7 +217,7 @@ func (c *PlanToEatClient) GetShoppingList(ctx context.Context) ([]models.Shoppin
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
- defer resp.Body.Close()
+ defer func() { _ = resp.Body.Close() }()
log.Printf("DEBUG [PlanToEat/Shopping]: Response status %d", resp.StatusCode)
diff --git a/internal/api/research_test.go b/internal/api/research_test.go
index 83a52b4..f2519e2 100644
--- a/internal/api/research_test.go
+++ b/internal/api/research_test.go
@@ -45,7 +45,7 @@ func TestTodoistSyncResearch(t *testing.T) {
if err != nil {
t.Fatalf("Failed to call Sync API: %v", err)
}
- defer resp.Body.Close()
+ defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(resp.Body)
if err != nil {
@@ -102,13 +102,13 @@ func TestTodoistSyncResearch(t *testing.T) {
if err != nil {
t.Fatalf("Incremental sync failed: %v", err)
}
- defer resp2.Body.Close()
+ defer func() { _ = resp2.Body.Close() }()
body2, _ := io.ReadAll(resp2.Body)
t.Logf("Incremental response size: %d bytes (vs full: %d bytes)", len(body2), len(body))
var syncResp2 map[string]interface{}
- json.Unmarshal(body2, &syncResp2)
+ _ = json.Unmarshal(body2, &syncResp2)
if items2, ok := syncResp2["items"].([]interface{}); ok {
t.Logf("Incremental items count: %d", len(items2))
}
@@ -142,7 +142,7 @@ func TestTrelloOptimizationResearch(t *testing.T) {
t.Fatalf("Failed to fetch boards: %v", err)
}
body, _ := io.ReadAll(resp.Body)
- resp.Body.Close()
+ _ = resp.Body.Close()
fullDuration := time.Since(start)
t.Logf("Test 1 - Full boards response:")
@@ -150,7 +150,7 @@ func TestTrelloOptimizationResearch(t *testing.T) {
t.Logf(" Duration: %v", fullDuration)
var boards []map[string]interface{}
- json.Unmarshal(body, &boards)
+ _ = json.Unmarshal(body, &boards)
t.Logf(" Board count: %d", len(boards))
if len(boards) > 0 {
t.Logf(" Fields in first board: %v", getKeys(boards[0]))
@@ -170,7 +170,7 @@ func TestTrelloOptimizationResearch(t *testing.T) {
t.Fatalf("Failed to fetch limited boards: %v", err)
}
body2, _ := io.ReadAll(resp2.Body)
- resp2.Body.Close()
+ _ = resp2.Body.Close()
limitedDuration := time.Since(start)
t.Logf("\nTest 2 - Limited fields (id,name):")
@@ -196,7 +196,7 @@ func TestTrelloOptimizationResearch(t *testing.T) {
t.Fatalf("Failed to fetch board with cards: %v", err)
}
body3, _ := io.ReadAll(resp3.Body)
- resp3.Body.Close()
+ _ = resp3.Body.Close()
batchDuration := time.Since(start)
t.Logf("\nTest 3 - Single board with cards/lists embedded:")
@@ -204,7 +204,7 @@ func TestTrelloOptimizationResearch(t *testing.T) {
t.Logf(" Duration: %v", batchDuration)
var boardWithCards map[string]interface{}
- json.Unmarshal(body3, &boardWithCards)
+ _ = json.Unmarshal(body3, &boardWithCards)
if cards, ok := boardWithCards["cards"].([]interface{}); ok {
t.Logf(" Cards count: %d", len(cards))
}
@@ -227,7 +227,7 @@ func TestTrelloOptimizationResearch(t *testing.T) {
t.Logf(" 'since' parameter: Error - %v", err)
} else {
body4, _ := io.ReadAll(resp4.Body)
- resp4.Body.Close()
+ _ = resp4.Body.Close()
t.Logf(" 'since' parameter: Status %d, Size %d bytes", resp4.StatusCode, len(body4))
}
}
diff --git a/internal/api/todoist_test.go b/internal/api/todoist_test.go
index 2fa6e28..7bbcc1e 100644
--- a/internal/api/todoist_test.go
+++ b/internal/api/todoist_test.go
@@ -13,7 +13,7 @@ import (
// newTestTodoistClient creates a TodoistClient for testing with custom base URL
func newTestTodoistClient(baseURL, apiKey string) *TodoistClient {
client := NewTodoistClient(apiKey)
- client.BaseClient.BaseURL = baseURL
+ client.BaseURL = baseURL
client.syncClient.BaseURL = baseURL
return client
}
@@ -62,7 +62,7 @@ func TestTodoistClient_CreateTask(t *testing.T) {
}
w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(response)
+ _ = json.NewEncoder(w).Encode(response)
}))
defer server.Close()
@@ -96,7 +96,7 @@ func TestTodoistClient_CreateTask_WithDueDate(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Parse JSON body
var payload map[string]interface{}
- json.NewDecoder(r.Body).Decode(&payload)
+ _ = json.NewDecoder(r.Body).Decode(&payload)
// Verify due_date
if payload["due_date"] != "2026-01-15" {
@@ -117,7 +117,7 @@ func TestTodoistClient_CreateTask_WithDueDate(t *testing.T) {
}
w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(response)
+ _ = json.NewEncoder(w).Encode(response)
}))
defer server.Close()
@@ -181,7 +181,7 @@ func TestTodoistClient_CompleteTask_Error(t *testing.T) {
// Mock server that returns error
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
- w.Write([]byte(`{"error":"Task not found"}`))
+ _, _ = w.Write([]byte(`{"error":"Task not found"}`))
}))
defer server.Close()
@@ -218,7 +218,7 @@ func TestTodoistClient_GetProjects(t *testing.T) {
}
w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(response)
+ _ = json.NewEncoder(w).Encode(response)
}))
defer server.Close()
diff --git a/internal/api/trello_test.go b/internal/api/trello_test.go
index 7433ff0..d677363 100644
--- a/internal/api/trello_test.go
+++ b/internal/api/trello_test.go
@@ -15,7 +15,7 @@ import (
// newTestTrelloClient creates a TrelloClient for testing with custom base URL
func newTestTrelloClient(baseURL, apiKey, token string) *TrelloClient {
client := NewTrelloClient(apiKey, token)
- client.BaseClient.BaseURL = baseURL
+ client.BaseURL = baseURL
return client
}
@@ -67,7 +67,7 @@ func TestTrelloClient_CreateCard(t *testing.T) {
}
w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(response)
+ _ = json.NewEncoder(w).Encode(response)
}))
defer server.Close()
@@ -122,7 +122,7 @@ func TestTrelloClient_CreateCard_WithDueDate(t *testing.T) {
}
w.Header().Set("Content-Type", "application/json")
- json.NewEncoder(w).Encode(response)
+ _ = json.NewEncoder(w).Encode(response)
}))
defer server.Close()
@@ -176,7 +176,7 @@ func TestTrelloClient_UpdateCard(t *testing.T) {
// Return 200 OK
w.WriteHeader(http.StatusOK)
- w.Write([]byte(`{"id":"card-123","name":"Updated Name"}`))
+ _, _ = w.Write([]byte(`{"id":"card-123","name":"Updated Name"}`))
}))
defer server.Close()
@@ -201,7 +201,7 @@ func TestTrelloClient_UpdateCard_Error(t *testing.T) {
// Mock server that returns error
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadRequest)
- w.Write([]byte(`{"error":"Invalid card ID"}`))
+ _, _ = w.Write([]byte(`{"error":"Invalid card ID"}`))
}))
defer server.Close()