feat(linear): add project_id filter for sync (#938)

Add project_id filter for Linear sync

When linear.project_id is configured, bd linear sync will only fetch issues
belonging to that project instead of all team issues.

Closes #937
This commit is contained in:
Paddo
2026-01-08 14:45:00 +10:00
committed by GitHub
parent 3c9ceaa74d
commit 5254ade346
3 changed files with 41 additions and 0 deletions

View File

@@ -92,6 +92,7 @@ func (c *Client) WithEndpoint(endpoint string) *Client {
return &Client{
APIKey: c.APIKey,
TeamID: c.TeamID,
ProjectID: c.ProjectID,
Endpoint: endpoint,
HTTPClient: c.HTTPClient,
}
@@ -103,11 +104,24 @@ func (c *Client) WithHTTPClient(httpClient *http.Client) *Client {
return &Client{
APIKey: c.APIKey,
TeamID: c.TeamID,
ProjectID: c.ProjectID,
Endpoint: c.Endpoint,
HTTPClient: httpClient,
}
}
// WithProjectID returns a new client configured to filter issues by the specified project.
// When set, FetchIssues and FetchIssuesSince will only return issues belonging to this project.
func (c *Client) WithProjectID(projectID string) *Client {
return &Client{
APIKey: c.APIKey,
TeamID: c.TeamID,
ProjectID: projectID,
Endpoint: c.Endpoint,
HTTPClient: c.HTTPClient,
}
}
// Execute sends a GraphQL request to the Linear API.
// Handles rate limiting with exponential backoff.
func (c *Client) Execute(ctx context.Context, req *GraphQLRequest) (json.RawMessage, error) {
@@ -178,6 +192,7 @@ func (c *Client) Execute(ctx context.Context, req *GraphQLRequest) (json.RawMess
// FetchIssues retrieves issues from Linear with optional filtering by state.
// state can be: "open" (unstarted/started), "closed" (completed/canceled), or "all".
// If ProjectID is set on the client, only issues from that project are returned.
func (c *Client) FetchIssues(ctx context.Context, state string) ([]Issue, error) {
var allIssues []Issue
var cursor string
@@ -189,6 +204,16 @@ func (c *Client) FetchIssues(ctx context.Context, state string) ([]Issue, error)
},
},
}
// Add project filter if configured
if c.ProjectID != "" {
filter["project"] = map[string]interface{}{
"id": map[string]interface{}{
"eq": c.ProjectID,
},
}
}
switch state {
case "open":
filter["state"] = map[string]interface{}{
@@ -242,6 +267,7 @@ func (c *Client) FetchIssues(ctx context.Context, state string) ([]Issue, error)
// FetchIssuesSince retrieves issues from Linear that have been updated since the given time.
// This enables incremental sync by only fetching issues modified after the last sync.
// The state parameter can be: "open", "closed", or "all".
// If ProjectID is set on the client, only issues from that project are returned.
func (c *Client) FetchIssuesSince(ctx context.Context, state string, since time.Time) ([]Issue, error) {
var allIssues []Issue
var cursor string
@@ -260,6 +286,15 @@ func (c *Client) FetchIssuesSince(ctx context.Context, state string, since time.
},
}
// Add project filter if configured
if c.ProjectID != "" {
filter["project"] = map[string]interface{}{
"id": map[string]interface{}{
"eq": c.ProjectID,
},
}
}
// Add state filter if specified
switch state {
case "open":

View File

@@ -32,6 +32,7 @@ const (
type Client struct {
APIKey string
TeamID string
ProjectID string // Optional: filter issues to a specific project
Endpoint string // GraphQL endpoint URL (defaults to DefaultAPIEndpoint)
HTTPClient *http.Client
}