Class: LinearApi::SyncedIssue
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- LinearApi::SyncedIssue
- Defined in:
- app/models/linear_api/synced_issue.rb
Class Method Summary collapse
-
.find_open_for_fingerprint(fingerprint) ⇒ Object
Find existing open issue for this fingerprint.
-
.refresh_stale_issues! ⇒ Object
Refresh all stale issues using batch API call (avoids N+1).
-
.should_create_new?(fingerprint) ⇒ Boolean
Check if we should create a new issue or add to existing.
Instance Method Summary collapse
-
#linear_url ⇒ Object
Build Linear URL using configurable workspace slug.
-
#open? ⇒ Boolean
Check if this issue is still open in Linear.
-
#parsed_metadata ⇒ Object
Parse metadata JSON.
-
#refresh_from_linear! ⇒ Object
Sync state from Linear.
- #resolved? ⇒ Boolean
Class Method Details
.find_open_for_fingerprint(fingerprint) ⇒ Object
Find existing open issue for this fingerprint
62 63 64 |
# File 'app/models/linear_api/synced_issue.rb', line 62 def find_open_for_fingerprint(fingerprint) by_fingerprint(fingerprint).unresolved.order(created_at: :desc).first end |
.refresh_stale_issues! ⇒ Object
Refresh all stale issues using batch API call (avoids N+1)
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'app/models/linear_api/synced_issue.rb', line 72 def refresh_stale_issues! stale_issues = stale.to_a return if stale_issues.empty? LinearApi.logger.info { "LinearApi: refreshing #{stale_issues.size} stale issues" } # Batch fetch from Linear API in groups of 50 stale_issues.each_slice(50) do |batch| ids = batch.map(&:linear_id) result = LinearApi.client.batch_get_issues(ids: ids) unless result.success? LinearApi.logger.error { "LinearApi: batch refresh failed: #{result.error}" } # Fall back to individual refresh for this batch batch.each(&:refresh_from_linear!) next end # Index fetched issues by ID for O(1) lookup fetched = result.data.index_by(&:id) batch.each do |synced| linear_issue = fetched[synced.linear_id] if linear_issue synced.update!( state_name: linear_issue.state_name, title: linear_issue.title, priority: linear_issue.priority, synced_at: Time.current ) else LinearApi.logger.warn { "LinearApi: issue #{synced.identifier} not found in Linear (may be deleted)" } end end end end |
.should_create_new?(fingerprint) ⇒ Boolean
Check if we should create a new issue or add to existing
67 68 69 |
# File 'app/models/linear_api/synced_issue.rb', line 67 def should_create_new?(fingerprint) find_open_for_fingerprint(fingerprint).nil? end |
Instance Method Details
#linear_url ⇒ Object
Build Linear URL using configurable workspace slug
46 47 48 49 |
# File 'app/models/linear_api/synced_issue.rb', line 46 def linear_url slug = LinearApi.workspace_slug || 'theownerstack' "https://linear.app/#{slug}/issue/#{identifier}" end |
#open? ⇒ Boolean
Check if this issue is still open in Linear
23 24 25 |
# File 'app/models/linear_api/synced_issue.rb', line 23 def open? !%w[Done Canceled Duplicate].include?(state_name) end |
#parsed_metadata ⇒ Object
Parse metadata JSON
52 53 54 55 56 57 58 |
# File 'app/models/linear_api/synced_issue.rb', line 52 def return {} unless .is_a?(String) ? JSON.parse() : rescue JSON::ParserError {} end |
#refresh_from_linear! ⇒ Object
Sync state from Linear
32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'app/models/linear_api/synced_issue.rb', line 32 def refresh_from_linear! result = LinearApi.client.get_issue_by_id(linear_id) return false unless result.success? update!( state_name: result.data.state_name, title: result.data.title, priority: result.data.priority, synced_at: Time.current ) true end |
#resolved? ⇒ Boolean
27 28 29 |
# File 'app/models/linear_api/synced_issue.rb', line 27 def resolved? state_name == 'Done' end |