linear

package
v0.1.0-alpha.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 2, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DefaultGraphQLEndpoint is the Linear GraphQL API endpoint
	DefaultGraphQLEndpoint = "https://api.linear.app/graphql"

	// DefaultTimeout for HTTP requests
	DefaultTimeout = 30 * time.Second
)

Variables

This section is empty.

Functions

func FormatBeadDescription

func FormatBeadDescription(issue *Issue) string

FormatBeadDescription formats a bead description with Linear metadata Appends Linear-specific information to the description

func MapPriority

func MapPriority(priority int) string

MapPriority converts Linear priority (0-4) to Beads priority (P0-P4) Linear: 0=Urgent, 1=High, 2=Medium, 3=Low, 4=No priority Beads: P0=Critical, P1=High, P2=Medium, P3=Low, P4=Backlog

func MapStatus

func MapStatus(state State) string

MapStatus converts Linear state type to Beads status Linear state types: "unstarted", "started", "completed", "canceled" Beads statuses: "open", "in_progress", "closed"

func MapType

func MapType(issue *Issue) string

MapType infers a Beads issue type from Linear data Returns: "task", "bug", or "feature"

func ParseIssueIDOrURL

func ParseIssueIDOrURL(input string) (string, error)

ParseIssueIDOrURL extracts the Linear issue identifier from a URL or ID string Accepts formats:

Types

type BeadCreateOptions

type BeadCreateOptions struct {
	Title       string
	Description string
	Type        string   // task, bug, feature
	Priority    string   // P0-P4
	Status      string   // open, in_progress, closed
	Assignee    string   // username or email
	Labels      []string // label names
	Metadata    map[string]string
}

BeadCreateOptions represents options for creating a bead from Linear

func MapIssueToBeadCreate

func MapIssueToBeadCreate(issue *Issue) *BeadCreateOptions

MapIssueToBeadCreate converts a Linear issue to Beads creation options

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is a Linear GraphQL API client

func NewClient

func NewClient(apiKey string) (*Client, error)

NewClient creates a new Linear GraphQL API client

func (*Client) GetIssue

func (c *Client) GetIssue(ctx context.Context, issueIDOrURL string) (*Issue, error)

GetIssue fetches a single issue by ID or URL

func (*Client) GetIssueComments

func (c *Client) GetIssueComments(ctx context.Context, issueID string) ([]Comment, error)

GetIssueComments fetches comments for an issue

func (*Client) ListIssues

func (c *Client) ListIssues(ctx context.Context, filters map[string]any) ([]*Issue, error)

ListIssues lists issues with optional filters Supported filter keys: status, priority, assignee

func (*Client) SearchIssues

func (c *Client) SearchIssues(ctx context.Context, searchQuery string, filters map[string]any) ([]*Issue, error)

SearchIssues searches for issues using a text query Note: The filters parameter is kept for API compatibility but Linear's issueSearch only supports a text query. Use ListIssues for filtered queries.

func (*Client) SetEndpoint

func (c *Client) SetEndpoint(endpoint string)

SetEndpoint sets a custom GraphQL endpoint (useful for testing)

type ClientInterface

type ClientInterface interface {
	// GetIssue fetches a single issue by ID or URL.
	GetIssue(ctx context.Context, issueIDOrURL string) (*Issue, error)
	// SearchIssues searches for issues using a text query.
	SearchIssues(ctx context.Context, searchQuery string, filters map[string]any) ([]*Issue, error)
	// ListIssues lists issues with optional filters.
	ListIssues(ctx context.Context, filters map[string]any) ([]*Issue, error)
	// GetIssueComments fetches comments for an issue.
	GetIssueComments(ctx context.Context, issueID string) ([]Comment, error)
}

ClientInterface defines the interface for Linear API operations. This abstraction enables testing without HTTP calls.

type Comment

type Comment struct {
	ID        string    `json:"id"`
	Body      string    `json:"body"`
	CreatedAt time.Time `json:"createdAt"`
	User      User      `json:"user"`
}

Comment represents a Linear comment

type Fetcher

type Fetcher struct {
	// contains filtered or unexported fields
}

Fetcher orchestrates fetching Linear issues and importing them into Beads

func NewFetcher

func NewFetcher(apiKey string, beadsDir string) (*Fetcher, error)

NewFetcher creates a new fetcher with the given API key and beads directory

func (*Fetcher) FetchAndImport

func (f *Fetcher) FetchAndImport(ctx context.Context, linearIDOrURL string, opts *ImportOptions) (*ImportResult, error)

FetchAndImport fetches a Linear issue and imports it into Beads Returns the created bead ID and any error

func (*Fetcher) FetchBatch

func (f *Fetcher) FetchBatch(ctx context.Context, linearIDsOrURLs []string, opts *ImportOptions) ([]*ImportResult, error)

FetchBatch fetches and imports multiple Linear issues

type ImportOptions

type ImportOptions struct {
	DryRun         bool
	UpdateExisting bool // Update existing beads if already imported
	CreateDeps     bool
	MaxDepDepth    int
	AssigneeFilter string
	StatusFilter   string
	PriorityFilter string
	TypeFilter     string
}

ImportOptions represents options for importing Linear issues

type ImportResult

type ImportResult struct {
	LinearID   string
	LinearURL  string
	BeadID     string
	Success    bool
	Error      error
	SkipReason string // e.g., "already imported", "filtered out"
}

ImportResult represents the result of importing a Linear issue

type Issue

type Issue struct {
	ID          string    `json:"id"`
	Identifier  string    `json:"identifier"` // e.g., "ENG-123"
	Title       string    `json:"title"`
	Description string    `json:"description"`
	Priority    int       `json:"priority"` // 0-4
	State       State     `json:"state"`
	URL         string    `json:"url"`
	CreatedAt   time.Time `json:"createdAt"`
	UpdatedAt   time.Time `json:"updatedAt"`

	// Optional fields
	Assignee *User     `json:"assignee,omitempty"`
	Project  *Project  `json:"project,omitempty"`
	Labels   []Label   `json:"labels,omitempty"`
	Estimate *float64  `json:"estimate,omitempty"`
	Comments []Comment `json:"comments,omitempty"`

	// Dependencies
	BlockedBy []string `json:"blockedBy,omitempty"` // Issue IDs
}

Issue represents a Linear issue with all relevant fields for import

type Label

type Label struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

Label represents a Linear label

type LinearClientMock

type LinearClientMock struct {
	// GetIssueFunc mocks the GetIssue method.
	GetIssueFunc func(ctx context.Context, issueIDOrURL string) (*Issue, error)

	// GetIssueCommentsFunc mocks the GetIssueComments method.
	GetIssueCommentsFunc func(ctx context.Context, issueID string) ([]Comment, error)

	// ListIssuesFunc mocks the ListIssues method.
	ListIssuesFunc func(ctx context.Context, filters map[string]any) ([]*Issue, error)

	// SearchIssuesFunc mocks the SearchIssues method.
	SearchIssuesFunc func(ctx context.Context, searchQuery string, filters map[string]any) ([]*Issue, error)
	// contains filtered or unexported fields
}

LinearClientMock is a mock implementation of ClientInterface.

func TestSomethingThatUsesClientInterface(t *testing.T) {

	// make and configure a mocked ClientInterface
	mockedClientInterface := &LinearClientMock{
		GetIssueFunc: func(ctx context.Context, issueIDOrURL string) (*Issue, error) {
			panic("mock out the GetIssue method")
		},
		GetIssueCommentsFunc: func(ctx context.Context, issueID string) ([]Comment, error) {
			panic("mock out the GetIssueComments method")
		},
		ListIssuesFunc: func(ctx context.Context, filters map[string]any) ([]*Issue, error) {
			panic("mock out the ListIssues method")
		},
		SearchIssuesFunc: func(ctx context.Context, searchQuery string, filters map[string]any) ([]*Issue, error) {
			panic("mock out the SearchIssues method")
		},
	}

	// use mockedClientInterface in code that requires ClientInterface
	// and then make assertions.

}

func (*LinearClientMock) GetIssue

func (mock *LinearClientMock) GetIssue(ctx context.Context, issueIDOrURL string) (*Issue, error)

GetIssue calls GetIssueFunc.

func (*LinearClientMock) GetIssueCalls

func (mock *LinearClientMock) GetIssueCalls() []struct {
	Ctx          context.Context
	IssueIDOrURL string
}

GetIssueCalls gets all the calls that were made to GetIssue. Check the length with:

len(mockedClientInterface.GetIssueCalls())

func (*LinearClientMock) GetIssueComments

func (mock *LinearClientMock) GetIssueComments(ctx context.Context, issueID string) ([]Comment, error)

GetIssueComments calls GetIssueCommentsFunc.

func (*LinearClientMock) GetIssueCommentsCalls

func (mock *LinearClientMock) GetIssueCommentsCalls() []struct {
	Ctx     context.Context
	IssueID string
}

GetIssueCommentsCalls gets all the calls that were made to GetIssueComments. Check the length with:

len(mockedClientInterface.GetIssueCommentsCalls())

func (*LinearClientMock) ListIssues

func (mock *LinearClientMock) ListIssues(ctx context.Context, filters map[string]any) ([]*Issue, error)

ListIssues calls ListIssuesFunc.

func (*LinearClientMock) ListIssuesCalls

func (mock *LinearClientMock) ListIssuesCalls() []struct {
	Ctx     context.Context
	Filters map[string]any
}

ListIssuesCalls gets all the calls that were made to ListIssues. Check the length with:

len(mockedClientInterface.ListIssuesCalls())

func (*LinearClientMock) SearchIssues

func (mock *LinearClientMock) SearchIssues(ctx context.Context, searchQuery string, filters map[string]any) ([]*Issue, error)

SearchIssues calls SearchIssuesFunc.

func (*LinearClientMock) SearchIssuesCalls

func (mock *LinearClientMock) SearchIssuesCalls() []struct {
	Ctx         context.Context
	SearchQuery string
	Filters     map[string]any
}

SearchIssuesCalls gets all the calls that were made to SearchIssues. Check the length with:

len(mockedClientInterface.SearchIssuesCalls())

type Project

type Project struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

Project represents a Linear project

type State

type State struct {
	ID   string `json:"id"`
	Name string `json:"name"` // e.g., "In Progress", "Done", "Todo"
	Type string `json:"type"` // e.g., "unstarted", "started", "completed", "canceled"
}

State represents the workflow state of an issue

type User

type User struct {
	ID    string `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}

User represents a Linear user

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL