feat: Linear Integration (#655)
* Add Linear integration CLI with sync and status commands - Add `bd linear sync` for bidirectional issue sync with Linear - Add `bd linear status` to show configuration and sync state - Stub pull/push functions pending GraphQL client (bd-b6b.2) * Implement Linear GraphQL client with full sync support - Add LinearClient with auth, fetch, create, update methods - Implement pull/push operations with Beads type mapping - Clean up redundant comments and remove unused code * Add configurable data mapping and dependency sync for Linear - Add LinearMappingConfig with configurable priority/state/label/relation maps - Import parent-child and issue relations as Beads dependencies - Support custom workflow states via linear.state_map.* config * Add incremental sync support for Linear integration - Add FetchIssuesSince() method using updatedAt filter in GraphQL - Check linear.last_sync config to enable incremental pulls - Track sync mode (incremental vs full) in LinearPullStats * feat(linear): implement push updates for existing Linear issues Add FetchIssueByIdentifier method to retrieve single issues by identifier (e.g., "TEAM-123") for timestamp comparison during push. Update doPushToLinear to: - Fetch Linear issue to get internal ID and UpdatedAt timestamp - Compare timestamps: only update if local is newer - Build update payload with title, description, priority, and state - Call UpdateIssue for issues where local has newer changes Closes bd-b6b.5 * Implement Linear conflict resolution strategies - Add true conflict detection by fetching Linear timestamps via API - Implement --prefer-linear resolution (re-import from Linear) - Implement timestamp-based resolution (newer wins as default) - Fix linter issues: handle resp.Body.Close() and remove unused error return * Add Linear integration tests and documentation - Add comprehensive unit tests for Linear mapping (priority, state, labels, relations) - Update docs/CONFIG.md with Linear configuration reference - Add examples/linear-workflow guide for bidirectional sync - Remove AI section header comments from tests * Fix Linear GraphQL filter construction and improve test coverage - Refactor filter handling to combine team ID into main filter object - Add test for duplicate issue relation mapping - Add HTTP round-trip helper for testing request payload validation * Refactor Linear queries to use shared constant and add UUID validation - Extract linearIssuesQuery to deduplicate FetchIssues/FetchIssuesSince - Add linearMaxPageSize constant and UUID validation with regex - Expand test coverage for new functionality * Refactor Linear integration into internal/linear package - Extract types, client, and mapping logic from cmd/bd/linear.go - Create internal/linear/ package for better code organization - Update tests to work with new package structure * Add linear teams command to list available teams - Add FetchTeams GraphQL query to Linear client - Refactor config reading to support daemon mode - Add tests for teams listing functionality * Refactor Linear config to use getLinearConfig helper - Consolidate config/env var lookup using getLinearConfig function - Add LINEAR_TEAM_ID environment variable support - Update error messages to include env var configuration options * Add hash ID generation and improve Linear conflict detection - Add configurable hash ID mode for Linear imports (matches bd/Jira) - Improve conflict detection with content hash comparison - Enhance conflict resolution with skip/force update tracking * Fix test for updated doPushToLinear signature - Add missing skipUpdateIDs parameter to test call
This commit is contained in:
107
docs/CONFIG.md
107
docs/CONFIG.md
@@ -377,17 +377,108 @@ bd config set jira.type_map.task "Task"
|
||||
|
||||
### Example: Linear Integration
|
||||
|
||||
```bash
|
||||
# Configure Linear connection
|
||||
bd config set linear.api_token "YOUR_TOKEN"
|
||||
bd config set linear.team_id "team-123"
|
||||
Linear integration provides bidirectional sync between bd and Linear via GraphQL API.
|
||||
|
||||
# Map statuses
|
||||
bd config set linear.status_map.open "Backlog"
|
||||
bd config set linear.status_map.in_progress "In Progress"
|
||||
bd config set linear.status_map.closed "Done"
|
||||
**Required configuration:**
|
||||
|
||||
```bash
|
||||
# API Key (can also use LINEAR_API_KEY environment variable)
|
||||
bd config set linear.api_key "lin_api_YOUR_API_KEY"
|
||||
|
||||
# Team ID (find in Linear team settings or URL)
|
||||
bd config set linear.team_id "team-uuid-here"
|
||||
```
|
||||
|
||||
**Getting your Linear credentials:**
|
||||
|
||||
1. **API Key**: Go to Linear → Settings → API → Personal API keys → Create key
|
||||
2. **Team ID**: Go to Linear → Settings → General → Team ID (or extract from URLs)
|
||||
|
||||
**Priority mapping (Linear 0-4 → Beads 0-4):**
|
||||
|
||||
Linear and Beads both use 0-4 priority scales, but with different semantics:
|
||||
- Linear: 0=no priority, 1=urgent, 2=high, 3=medium, 4=low
|
||||
- Beads: 0=critical, 1=high, 2=medium, 3=low, 4=backlog
|
||||
|
||||
Default mapping (configurable):
|
||||
|
||||
```bash
|
||||
bd config set linear.priority_map.0 4 # No priority -> Backlog
|
||||
bd config set linear.priority_map.1 0 # Urgent -> Critical
|
||||
bd config set linear.priority_map.2 1 # High -> High
|
||||
bd config set linear.priority_map.3 2 # Medium -> Medium
|
||||
bd config set linear.priority_map.4 3 # Low -> Low
|
||||
```
|
||||
|
||||
**State mapping (Linear state types → Beads statuses):**
|
||||
|
||||
Map Linear workflow state types to Beads statuses:
|
||||
|
||||
```bash
|
||||
bd config set linear.state_map.backlog open
|
||||
bd config set linear.state_map.unstarted open
|
||||
bd config set linear.state_map.started in_progress
|
||||
bd config set linear.state_map.completed closed
|
||||
bd config set linear.state_map.canceled closed
|
||||
|
||||
# For custom workflow states, use lowercase state name:
|
||||
bd config set linear.state_map.in_review in_progress
|
||||
bd config set linear.state_map.blocked blocked
|
||||
bd config set linear.state_map.on_hold blocked
|
||||
```
|
||||
|
||||
**Label to issue type mapping:**
|
||||
|
||||
Infer bd issue type from Linear labels:
|
||||
|
||||
```bash
|
||||
bd config set linear.label_type_map.bug bug
|
||||
bd config set linear.label_type_map.defect bug
|
||||
bd config set linear.label_type_map.feature feature
|
||||
bd config set linear.label_type_map.enhancement feature
|
||||
bd config set linear.label_type_map.epic epic
|
||||
bd config set linear.label_type_map.chore chore
|
||||
bd config set linear.label_type_map.maintenance chore
|
||||
bd config set linear.label_type_map.task task
|
||||
```
|
||||
|
||||
**Relation type mapping (Linear relations → Beads dependencies):**
|
||||
|
||||
```bash
|
||||
bd config set linear.relation_map.blocks blocks
|
||||
bd config set linear.relation_map.blockedBy blocks
|
||||
bd config set linear.relation_map.duplicate duplicates
|
||||
bd config set linear.relation_map.related related
|
||||
```
|
||||
|
||||
**Sync commands:**
|
||||
|
||||
```bash
|
||||
# Bidirectional sync (pull then push, with conflict resolution)
|
||||
bd linear sync
|
||||
|
||||
# Pull only (import from Linear)
|
||||
bd linear sync --pull
|
||||
|
||||
# Push only (export to Linear)
|
||||
bd linear sync --push
|
||||
|
||||
# Dry run (preview without changes)
|
||||
bd linear sync --dry-run
|
||||
|
||||
# Conflict resolution options
|
||||
bd linear sync --prefer-local # Local version wins on conflicts
|
||||
bd linear sync --prefer-linear # Linear version wins on conflicts
|
||||
# Default: newer timestamp wins
|
||||
|
||||
# Check sync status
|
||||
bd linear status
|
||||
```
|
||||
|
||||
**Automatic sync tracking:**
|
||||
|
||||
The `linear.last_sync` config key is automatically updated after each sync, enabling incremental sync (only fetch issues updated since last sync).
|
||||
|
||||
### Example: GitHub Integration
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user