linear

package
v0.30.0 Latest Latest
Warning

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

Go to latest
Published: Jul 27, 2026 License: Apache-2.0 Imports: 24 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// AuthorizeURL is where the user approves the OAuth application.
	AuthorizeURL = "https://linear.app/oauth/authorize"

	// TokenURL exchanges authorization codes and refresh tokens for access tokens.
	TokenURL = "https://api.linear.app/oauth/token"

	// AppsNewURL is Linear's OAuth application creation form. There is no API to
	// create OAuth apps, but the form accepts manifest query parameters that
	// pre-fill every field, so the user only has to click Create.
	AppsNewURL = "https://linear.app/settings/api/applications/new"
)
View Source
const (
	// IssuePayloadType is the payload type emitted for every Linear issue,
	// both by the createIssue action and the onIssue trigger.
	IssuePayloadType = "linear.issue"

	// SignatureHeader carries a hex-encoded HMAC-SHA256 of the raw request body.
	SignatureHeader = "Linear-Signature"

	// EventHeader carries the resource type that triggered the delivery, e.g. "Issue".
	EventHeader = "Linear-Event"

	// IssueResourceType is the Linear webhook resource type for issue events.
	IssueResourceType = "Issue"
)
View Source
const (
	OAuthAccessToken  = "accessToken"
	OAuthRefreshToken = "refreshToken"
)
View Source
const (
	ResourceTypeTeam          = "team"
	ResourceTypeWorkflowState = "workflowState"
	ResourceTypeMember        = "member"
	ResourceTypeLabel         = "label"
	ResourceTypeProject       = "project"
)
View Source
const APIURL = "https://api.linear.app/graphql"

APIURL is Linear's single GraphQL endpoint. Linear has no REST API.

Variables

This section is empty.

Functions

func ListTeams

ListTeams reads the teams captured during sync, so the picker stays responsive and does not spend Linear's per-user request budget on every render.

Types

type Auth

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

func NewAuth

func NewAuth(client core.HTTPContext) *Auth

func (*Auth) ExchangeCode

func (a *Auth) ExchangeCode(clientID, clientSecret, code, redirectURI string) (*TokenResponse, error)

func (*Auth) HandleCallback

func (a *Auth) HandleCallback(req *http.Request, clientID, clientSecret, expectedState, redirectURI string) (*TokenResponse, error)

func (*Auth) RefreshToken

func (a *Auth) RefreshToken(clientID, clientSecret, refreshToken string) (*TokenResponse, error)

type Client

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

Client talks to Linear's GraphQL API using an OAuth access token, which Linear expects with a "Bearer " prefix — unlike personal API keys.

func NewClient

func NewClient(httpCtx core.HTTPContext, ctx core.IntegrationContext) (*Client, error)

func (*Client) CreateIssue

func (c *Client) CreateIssue(input map[string]any) (*Issue, error)

func (*Client) CreateWebhook

func (c *Client) CreateWebhook(url, secret, label, teamID string, resourceTypes []string) (*Webhook, error)

CreateWebhook registers a webhook on Linear. Managing webhooks requires a workspace admin or an OAuth token carrying the admin scope.

func (*Client) DeleteWebhook

func (c *Client) DeleteWebhook(id string) error

func (*Client) GetIssue

func (c *Client) GetIssue(id string) (*Issue, error)

GetIssue fetches a single issue. Linear accepts either the issue UUID or the human-readable identifier (e.g. ENG-142) as the id argument.

func (*Client) GetViewer

func (c *Client) GetViewer() (*Viewer, error)

func (*Client) ListLabels

func (c *Client) ListLabels(teamID string) ([]Label, error)

func (*Client) ListTeamMembers

func (c *Client) ListTeamMembers(teamID string) ([]User, error)

func (*Client) ListTeamProjects

func (c *Client) ListTeamProjects(teamID string) ([]Project, error)

func (*Client) ListTeams

func (c *Client) ListTeams() ([]Team, error)

func (*Client) ListWorkflowStates

func (c *Client) ListWorkflowStates(teamID string) ([]WorkflowState, error)

func (*Client) UpdateIssue

func (c *Client) UpdateIssue(id string, input map[string]any) (*Issue, error)

UpdateIssue applies the given IssueUpdateInput fields to an issue. Like GetIssue, the id may be the issue UUID or its identifier (e.g. ENG-142).

type CreateIssue

type CreateIssue struct{}

func (*CreateIssue) Cancel

func (c *CreateIssue) Cancel(ctx core.ExecutionContext) error

func (*CreateIssue) Cleanup

func (c *CreateIssue) Cleanup(ctx core.SetupContext) error

func (*CreateIssue) Color

func (c *CreateIssue) Color() string

func (*CreateIssue) Configuration

func (c *CreateIssue) Configuration() []configuration.Field

func (*CreateIssue) Description

func (c *CreateIssue) Description() string

func (*CreateIssue) Documentation

func (c *CreateIssue) Documentation() string

func (*CreateIssue) ExampleOutput

func (c *CreateIssue) ExampleOutput() map[string]any

func (*CreateIssue) Execute

func (c *CreateIssue) Execute(ctx core.ExecutionContext) error

func (*CreateIssue) HandleHook

func (c *CreateIssue) HandleHook(ctx core.ActionHookContext) error

func (*CreateIssue) HandleWebhook

func (*CreateIssue) Hooks

func (c *CreateIssue) Hooks() []core.Hook

func (*CreateIssue) Icon

func (c *CreateIssue) Icon() string

func (*CreateIssue) Label

func (c *CreateIssue) Label() string

func (*CreateIssue) Name

func (c *CreateIssue) Name() string

func (*CreateIssue) OutputChannels

func (c *CreateIssue) OutputChannels(configuration any) []core.OutputChannel

func (*CreateIssue) ProcessQueueItem

func (c *CreateIssue) ProcessQueueItem(ctx core.ProcessQueueContext) (*uuid.UUID, error)

func (*CreateIssue) Setup

func (c *CreateIssue) Setup(ctx core.SetupContext) error

type CreateIssueSpec

type CreateIssueSpec struct {
	Team        string   `json:"team" mapstructure:"team"`
	Title       string   `json:"title" mapstructure:"title"`
	Description string   `json:"description" mapstructure:"description"`
	Project     string   `json:"project" mapstructure:"project"`
	State       string   `json:"state" mapstructure:"state"`
	Assignee    string   `json:"assignee" mapstructure:"assignee"`
	Priority    string   `json:"priority" mapstructure:"priority"`
	Labels      []string `json:"labels" mapstructure:"labels"`
}

type GetIssue

type GetIssue struct{}

func (*GetIssue) Cancel

func (c *GetIssue) Cancel(ctx core.ExecutionContext) error

func (*GetIssue) Cleanup

func (c *GetIssue) Cleanup(ctx core.SetupContext) error

func (*GetIssue) Color

func (c *GetIssue) Color() string

func (*GetIssue) Configuration

func (c *GetIssue) Configuration() []configuration.Field

func (*GetIssue) Description

func (c *GetIssue) Description() string

func (*GetIssue) Documentation

func (c *GetIssue) Documentation() string

func (*GetIssue) ExampleOutput

func (c *GetIssue) ExampleOutput() map[string]any

func (*GetIssue) Execute

func (c *GetIssue) Execute(ctx core.ExecutionContext) error

func (*GetIssue) HandleHook

func (c *GetIssue) HandleHook(ctx core.ActionHookContext) error

func (*GetIssue) HandleWebhook

func (*GetIssue) Hooks

func (c *GetIssue) Hooks() []core.Hook

func (*GetIssue) Icon

func (c *GetIssue) Icon() string

func (*GetIssue) Label

func (c *GetIssue) Label() string

func (*GetIssue) Name

func (c *GetIssue) Name() string

func (*GetIssue) OutputChannels

func (c *GetIssue) OutputChannels(configuration any) []core.OutputChannel

func (*GetIssue) ProcessQueueItem

func (c *GetIssue) ProcessQueueItem(ctx core.ProcessQueueContext) (*uuid.UUID, error)

func (*GetIssue) Setup

func (c *GetIssue) Setup(ctx core.SetupContext) error

type GetIssueSpec

type GetIssueSpec struct {
	Issue string `json:"issue" mapstructure:"issue"`
}

type Issue

type Issue struct {
	ID            string         `json:"id"`
	Identifier    string         `json:"identifier"`
	Number        int            `json:"number"`
	Title         string         `json:"title"`
	Description   string         `json:"description,omitempty"`
	URL           string         `json:"url"`
	Priority      int            `json:"priority"`
	PriorityLabel string         `json:"priorityLabel,omitempty"`
	BranchName    string         `json:"branchName,omitempty"`
	CreatedAt     string         `json:"createdAt,omitempty"`
	UpdatedAt     string         `json:"updatedAt,omitempty"`
	State         *WorkflowState `json:"state,omitempty"`
	Team          *Team          `json:"team,omitempty"`
	Assignee      *User          `json:"assignee,omitempty"`
	Creator       *User          `json:"creator,omitempty"`
	Project       *Project       `json:"project,omitempty"`
	Labels        LabelList      `json:"labels,omitempty"`
}

type Label

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

type LabelList

type LabelList []Label

LabelList flattens Linear's `labels { nodes { ... } }` connection into a plain array, so emitted payloads expose `labels[0].name` rather than `labels.nodes[0].name`. Null connections and null node lists decode as empty rather than failing: erroring here would fail the execution after the issue was already created on Linear, inviting duplicate-creating retries.

func (*LabelList) UnmarshalJSON

func (l *LabelList) UnmarshalJSON(data []byte) error

type Linear

type Linear struct{}

func (*Linear) Actions

func (l *Linear) Actions() []core.Action

func (*Linear) Cleanup

func (l *Linear) Cleanup(ctx core.IntegrationCleanupContext) error

func (*Linear) Configuration

func (l *Linear) Configuration() []configuration.Field

func (*Linear) Description

func (l *Linear) Description() string

func (*Linear) HandleHook

func (l *Linear) HandleHook(ctx core.IntegrationHookContext) error

func (*Linear) HandleRequest

func (l *Linear) HandleRequest(ctx core.HTTPRequestContext)

func (*Linear) Hooks

func (l *Linear) Hooks() []core.Hook

func (*Linear) Icon

func (l *Linear) Icon() string

func (*Linear) Instructions

func (l *Linear) Instructions() string

func (*Linear) Label

func (l *Linear) Label() string

func (*Linear) ListResources

func (l *Linear) ListResources(resourceType string, ctx core.ListResourcesContext) ([]core.IntegrationResource, error)

func (*Linear) Name

func (l *Linear) Name() string

func (*Linear) Sync

func (l *Linear) Sync(ctx core.SyncContext) error

func (*Linear) Triggers

func (l *Linear) Triggers() []core.Trigger

type LinearWebhookHandler

type LinearWebhookHandler struct{}

func (*LinearWebhookHandler) Cleanup

func (*LinearWebhookHandler) CompareConfig

func (h *LinearWebhookHandler) CompareConfig(a, b any) (bool, error)

func (*LinearWebhookHandler) Merge

func (h *LinearWebhookHandler) Merge(current, requested any) (any, bool, error)

func (*LinearWebhookHandler) Setup

type Metadata

type Metadata struct {
	State                *string `json:"state,omitempty" mapstructure:"state,omitempty"`
	User                 *User   `json:"user,omitempty" mapstructure:"user,omitempty"`
	Teams                []Team  `json:"teams" mapstructure:"teams"`
	Organization         string  `json:"organization,omitempty" mapstructure:"organization,omitempty"`
	URLKey               string  `json:"urlKey,omitempty" mapstructure:"urlKey,omitempty"`
	AccessTokenExpiresAt string  `json:"accessTokenExpiresAt,omitempty" mapstructure:"accessTokenExpiresAt,omitempty"`
}

type NodeMetadata

type NodeMetadata struct {
	Team *Team `json:"team,omitempty" mapstructure:"team,omitempty"`
}

NodeMetadata is stored on Linear nodes at setup time, so canvas cards can show the team without re-querying Linear.

type OnIssue

type OnIssue struct{}

func (*OnIssue) Cleanup

func (i *OnIssue) Cleanup(ctx core.TriggerContext) error

func (*OnIssue) Color

func (i *OnIssue) Color() string

func (*OnIssue) Configuration

func (i *OnIssue) Configuration() []configuration.Field

func (*OnIssue) Description

func (i *OnIssue) Description() string

func (*OnIssue) Documentation

func (i *OnIssue) Documentation() string

func (*OnIssue) ExampleData

func (i *OnIssue) ExampleData() map[string]any

func (*OnIssue) HandleHook

func (i *OnIssue) HandleHook(ctx core.TriggerHookContext) (map[string]any, error)

func (*OnIssue) HandleWebhook

func (i *OnIssue) HandleWebhook(ctx core.WebhookRequestContext) (int, *core.WebhookResponseBody, error)

func (*OnIssue) Hooks

func (i *OnIssue) Hooks() []core.Hook

func (*OnIssue) Icon

func (i *OnIssue) Icon() string

func (*OnIssue) Label

func (i *OnIssue) Label() string

func (*OnIssue) Name

func (i *OnIssue) Name() string

func (*OnIssue) Setup

func (i *OnIssue) Setup(ctx core.TriggerContext) error

type OnIssueConfiguration

type OnIssueConfiguration struct {
	Team    string                    `json:"team" mapstructure:"team"`
	Actions []string                  `json:"actions" mapstructure:"actions"`
	Labels  []configuration.Predicate `json:"labels" mapstructure:"labels"`
}

type Organization

type Organization struct {
	ID     string `json:"id"`
	Name   string `json:"name"`
	URLKey string `json:"urlKey"`
}

type Project

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

type Team

type Team struct {
	ID   string `json:"id"`
	Key  string `json:"key"`
	Name string `json:"name"`
}

type TokenResponse

type TokenResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int    `json:"expires_in"`
}

TokenResponse is Linear's token endpoint response. Since April 2026 Linear issues 24-hour access tokens with rotating refresh tokens, so both fields must be stored and refresh handled on resync.

func (*TokenResponse) ExpiresAt

func (t *TokenResponse) ExpiresAt() time.Time

ExpiresAt returns when the access token stops working, or the zero time when Linear did not report a lifetime.

func (*TokenResponse) GetExpiration

func (t *TokenResponse) GetExpiration() time.Duration

GetExpiration returns how long to wait before resyncing to refresh the token: half its lifetime, so one failed resync still leaves time to retry.

type UpdateIssue

type UpdateIssue struct{}

func (*UpdateIssue) Cancel

func (c *UpdateIssue) Cancel(ctx core.ExecutionContext) error

func (*UpdateIssue) Cleanup

func (c *UpdateIssue) Cleanup(ctx core.SetupContext) error

func (*UpdateIssue) Color

func (c *UpdateIssue) Color() string

func (*UpdateIssue) Configuration

func (c *UpdateIssue) Configuration() []configuration.Field

func (*UpdateIssue) Description

func (c *UpdateIssue) Description() string

func (*UpdateIssue) Documentation

func (c *UpdateIssue) Documentation() string

func (*UpdateIssue) ExampleOutput

func (c *UpdateIssue) ExampleOutput() map[string]any

func (*UpdateIssue) Execute

func (c *UpdateIssue) Execute(ctx core.ExecutionContext) error

func (*UpdateIssue) HandleHook

func (c *UpdateIssue) HandleHook(ctx core.ActionHookContext) error

func (*UpdateIssue) HandleWebhook

func (*UpdateIssue) Hooks

func (c *UpdateIssue) Hooks() []core.Hook

func (*UpdateIssue) Icon

func (c *UpdateIssue) Icon() string

func (*UpdateIssue) Label

func (c *UpdateIssue) Label() string

func (*UpdateIssue) Name

func (c *UpdateIssue) Name() string

func (*UpdateIssue) OutputChannels

func (c *UpdateIssue) OutputChannels(configuration any) []core.OutputChannel

func (*UpdateIssue) ProcessQueueItem

func (c *UpdateIssue) ProcessQueueItem(ctx core.ProcessQueueContext) (*uuid.UUID, error)

func (*UpdateIssue) Setup

func (c *UpdateIssue) Setup(ctx core.SetupContext) error

type UpdateIssueSpec

type UpdateIssueSpec struct {
	Team        string   `json:"team" mapstructure:"team"`
	Issue       string   `json:"issue" mapstructure:"issue"`
	Title       string   `json:"title" mapstructure:"title"`
	Description string   `json:"description" mapstructure:"description"`
	State       string   `json:"state" mapstructure:"state"`
	Assignee    string   `json:"assignee" mapstructure:"assignee"`
	Priority    string   `json:"priority" mapstructure:"priority"`
	Labels      []string `json:"labels" mapstructure:"labels"`
	Project     string   `json:"project" mapstructure:"project"`
}

type User

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

type Viewer

type Viewer struct {
	User         *User        `json:"viewer"`
	Organization Organization `json:"organization"`
}

Viewer identifies the account behind the access token and the workspace it belongs to.

type Webhook

type Webhook struct {
	ID     string `json:"id"`
	URL    string `json:"url"`
	Secret string `json:"secret,omitempty"`
}

type WebhookConfiguration

type WebhookConfiguration struct {
	TeamID       string `json:"teamId" mapstructure:"teamId"`
	ResourceType string `json:"resourceType" mapstructure:"resourceType"`
}

type WebhookMetadata

type WebhookMetadata struct {
	ID string `json:"id" mapstructure:"id"`
}

type WorkflowState

type WorkflowState struct {
	ID   string `json:"id"`
	Name string `json:"name"`
	Type string `json:"type,omitempty"`
}

Jump to

Keyboard shortcuts

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