Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
terraform-provider-coderabbit
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build install test clean
.PHONY: build install test clean lint

HOSTNAME=registry.terraform.io
NAMESPACE=coderabbitai
Expand Down Expand Up @@ -27,6 +27,9 @@ fmt:
vet:
go vet ./...

lint:
golangci-lint run

.PHONY: deps
deps:
go mod tidy
43 changes: 40 additions & 3 deletions internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"math"
"net/http"
"sync"
"time"
)

Expand Down Expand Up @@ -35,6 +36,10 @@ type Client struct {
GitHubToken string
HTTPClient *http.Client
RetryConfig RetryConfig

// Cache for seats response (valid for single terraform run)
seatsCache *SeatsResponse
seatsCacheMu sync.RWMutex
}

// NewClient creates a new CodeRabbit API client
Expand Down Expand Up @@ -153,7 +158,7 @@ func (c *Client) doRequest(method, path string, body any) ([]byte, error) {
}

respBody, err := io.ReadAll(resp.Body)
resp.Body.Close()
_ = resp.Body.Close()
if err != nil {
lastErr = fmt.Errorf("failed to read response body: %w", err)
continue
Expand Down Expand Up @@ -204,7 +209,7 @@ func (c *Client) GetGitUserID(githubID string) (string, error) {
}

respBody, err := io.ReadAll(resp.Body)
resp.Body.Close()
_ = resp.Body.Close()
if err != nil {
lastErr = fmt.Errorf("failed to read GitHub API response: %w", err)
continue
Expand Down Expand Up @@ -234,8 +239,26 @@ func (c *Client) GetGitUserID(githubID string) (string, error) {
return "", fmt.Errorf("GitHub API request failed after %d retries: %w", c.RetryConfig.MaxRetries, lastErr)
}

// GetSeats retrieves all seat assignments
// GetSeats retrieves all seat assignments (cached for the lifetime of the client)
func (c *Client) GetSeats() (*SeatsResponse, error) {
// Check cache first with read lock
c.seatsCacheMu.RLock()
if c.seatsCache != nil {
cached := c.seatsCache
c.seatsCacheMu.RUnlock()
return cached, nil
}
c.seatsCacheMu.RUnlock()

// Fetch from API with write lock
c.seatsCacheMu.Lock()
defer c.seatsCacheMu.Unlock()

// Double-check after acquiring write lock
if c.seatsCache != nil {
return c.seatsCache, nil
}

respBody, err := c.doRequest(http.MethodGet, "/seats/", nil)
if err != nil {
return nil, err
Expand All @@ -246,9 +269,17 @@ func (c *Client) GetSeats() (*SeatsResponse, error) {
return nil, fmt.Errorf("failed to unmarshal response: %w", err)
}

c.seatsCache = &seats
return &seats, nil
}

// InvalidateSeatsCache clears the seats cache, forcing a fresh fetch on next GetSeats call
func (c *Client) InvalidateSeatsCache() {
c.seatsCacheMu.Lock()
defer c.seatsCacheMu.Unlock()
c.seatsCache = nil
}

// AssignSeat assigns a seat to a user
func (c *Client) AssignSeat(gitUserID string) error {
reqBody := AssignSeatRequest{GitUserID: gitUserID}
Expand All @@ -266,6 +297,9 @@ func (c *Client) AssignSeat(gitUserID string) error {
return fmt.Errorf("seat assignment failed")
}

// Invalidate cache since seat state changed
c.InvalidateSeatsCache()

return nil
}

Expand All @@ -286,6 +320,9 @@ func (c *Client) UnassignSeat(gitUserID string) error {
return fmt.Errorf("seat unassignment failed")
}

// Invalidate cache since seat state changed
c.InvalidateSeatsCache()

return nil
}

Expand Down
Loading