linear_api 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +30 -0
- data/LICENSE.txt +21 -0
- data/README.md +371 -0
- data/app/models/linear_api/application_record.rb +8 -0
- data/app/models/linear_api/cached_metadata.rb +102 -0
- data/app/models/linear_api/synced_issue.rb +76 -0
- data/db/migrate/20260204000001_create_linear_api_cached_metadata.rb +22 -0
- data/db/migrate/20260204000002_create_linear_api_synced_issues.rb +26 -0
- data/lib/linear_api/cache_sync.rb +185 -0
- data/lib/linear_api/client.rb +519 -0
- data/lib/linear_api/engine.rb +27 -0
- data/lib/linear_api/issue.rb +169 -0
- data/lib/linear_api/issue_tracker.rb +291 -0
- data/lib/linear_api/label.rb +40 -0
- data/lib/linear_api/project.rb +43 -0
- data/lib/linear_api/result.rb +36 -0
- data/lib/linear_api/team.rb +51 -0
- data/lib/linear_api/version.rb +5 -0
- data/lib/linear_api.rb +41 -0
- data/lib/tasks/linear_api.rake +164 -0
- metadata +268 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :linear do
|
|
4
|
+
desc 'Setup auto-tracking infrastructure (creates project and label in Linear)'
|
|
5
|
+
task setup: :environment do
|
|
6
|
+
puts 'Setting up Linear auto-tracking infrastructure...'
|
|
7
|
+
|
|
8
|
+
result = LinearApi::IssueTracker.setup!
|
|
9
|
+
|
|
10
|
+
if result[:project_id]
|
|
11
|
+
puts " ✓ Project 'Auto-Tracked Errors' ready (#{result[:project_id]})"
|
|
12
|
+
else
|
|
13
|
+
puts " ✗ Failed to create/find project"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
if result[:label_id]
|
|
17
|
+
puts " ✓ Label 'auto:tracked' ready (#{result[:label_id]})"
|
|
18
|
+
else
|
|
19
|
+
puts " ✗ Failed to create/find label"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
puts "\nSetup complete! Auto-tracked issues will be created in the 'Auto-Tracked Errors' project."
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc 'Sync all metadata from Linear API (labels, projects, states, users)'
|
|
26
|
+
task sync_cache: :environment do
|
|
27
|
+
puts 'Syncing Linear metadata from API...'
|
|
28
|
+
|
|
29
|
+
results = LinearApi::CacheSync.sync_all
|
|
30
|
+
|
|
31
|
+
results.each do |type, result|
|
|
32
|
+
if result[:success]
|
|
33
|
+
puts " ✓ #{type}: #{result[:count]} items synced"
|
|
34
|
+
else
|
|
35
|
+
puts " ✗ #{type}: #{result[:error]}"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
puts "\nCache sync complete!"
|
|
40
|
+
puts "Total cached:"
|
|
41
|
+
puts " - #{LinearApi::CachedMetadata.labels.count} labels"
|
|
42
|
+
puts " - #{LinearApi::CachedMetadata.projects.count} projects"
|
|
43
|
+
puts " - #{LinearApi::CachedMetadata.states.count} states"
|
|
44
|
+
puts " - #{LinearApi::CachedMetadata.users.count} users"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
desc 'Import labels/states/projects from linear.json (read-only reference data only)'
|
|
48
|
+
task import_json: :environment do
|
|
49
|
+
json_path = ENV['LINEAR_JSON_PATH'] || Rails.root.join('../linear.json')
|
|
50
|
+
|
|
51
|
+
unless File.exist?(json_path)
|
|
52
|
+
puts "Error: linear.json not found at #{json_path}"
|
|
53
|
+
puts 'Set LINEAR_JSON_PATH environment variable to specify a different path.'
|
|
54
|
+
exit 1
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
puts "Importing reference data from #{json_path}..."
|
|
58
|
+
puts "(This only imports labels, states, and users - not issues)"
|
|
59
|
+
|
|
60
|
+
counts = LinearApi::CacheSync.import_from_json(json_path)
|
|
61
|
+
|
|
62
|
+
puts "\nImport complete!"
|
|
63
|
+
puts " - #{counts[:labels]} labels"
|
|
64
|
+
puts " - #{counts[:projects]} projects (reference only)"
|
|
65
|
+
puts " - #{counts[:states]} states"
|
|
66
|
+
puts " - #{counts[:users]} users"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
desc 'Export cached metadata to JSON file'
|
|
70
|
+
task export_cache: :environment do
|
|
71
|
+
output_path = ENV['LINEAR_EXPORT_PATH'] || Rails.root.join('linear_cache.json')
|
|
72
|
+
|
|
73
|
+
data = {
|
|
74
|
+
last_updated: Time.current.iso8601,
|
|
75
|
+
team: {
|
|
76
|
+
id: LinearApi.team_id,
|
|
77
|
+
key: 'TOS'
|
|
78
|
+
},
|
|
79
|
+
workflow_states: export_states,
|
|
80
|
+
labels: export_labels,
|
|
81
|
+
projects: export_projects,
|
|
82
|
+
users: export_users
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
File.write(output_path, JSON.pretty_generate(data))
|
|
86
|
+
puts "Exported cache to #{output_path}"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
desc 'Refresh stale synced issues from Linear'
|
|
90
|
+
task refresh_issues: :environment do
|
|
91
|
+
stale_count = LinearApi::SyncedIssue.stale.count
|
|
92
|
+
puts "Refreshing #{stale_count} stale issues..."
|
|
93
|
+
|
|
94
|
+
LinearApi::SyncedIssue.refresh_stale_issues!
|
|
95
|
+
|
|
96
|
+
puts 'Done!'
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
desc 'Show cache statistics'
|
|
100
|
+
task stats: :environment do
|
|
101
|
+
puts 'Linear API Cache Statistics'
|
|
102
|
+
puts '=' * 40
|
|
103
|
+
puts "\nCached Metadata:"
|
|
104
|
+
puts " Labels: #{LinearApi::CachedMetadata.labels.count}"
|
|
105
|
+
puts " Projects: #{LinearApi::CachedMetadata.projects.count}"
|
|
106
|
+
puts " States: #{LinearApi::CachedMetadata.states.count}"
|
|
107
|
+
puts " Users: #{LinearApi::CachedMetadata.users.count}"
|
|
108
|
+
|
|
109
|
+
puts "\nSynced Issues:"
|
|
110
|
+
puts " Total: #{LinearApi::SyncedIssue.count}"
|
|
111
|
+
puts " Unresolved: #{LinearApi::SyncedIssue.unresolved.count}"
|
|
112
|
+
puts " Resolved: #{LinearApi::SyncedIssue.resolved.count}"
|
|
113
|
+
puts " Recent (7d): #{LinearApi::SyncedIssue.recent.count}"
|
|
114
|
+
puts " Stale: #{LinearApi::SyncedIssue.stale.count}"
|
|
115
|
+
|
|
116
|
+
puts "\nLabel Categories:"
|
|
117
|
+
LinearApi::CachedMetadata.labels.group(:category).count.each do |category, count|
|
|
118
|
+
puts " #{category || 'uncategorized'}: #{count}"
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Helper methods for export
|
|
123
|
+
def export_states
|
|
124
|
+
LinearApi::CachedMetadata.states.each_with_object({}) do |state, hash|
|
|
125
|
+
hash[state.key] = {
|
|
126
|
+
id: state.linear_id,
|
|
127
|
+
name: state.name,
|
|
128
|
+
type: state.state_type
|
|
129
|
+
}
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def export_labels
|
|
134
|
+
LinearApi::CachedMetadata.labels.group_by(&:category).transform_values do |labels|
|
|
135
|
+
labels.each_with_object({}) do |label, hash|
|
|
136
|
+
key = label.key.split(':').last
|
|
137
|
+
hash[key] = {
|
|
138
|
+
id: label.linear_id,
|
|
139
|
+
name: label.name,
|
|
140
|
+
color: label.color
|
|
141
|
+
}
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def export_projects
|
|
147
|
+
LinearApi::CachedMetadata.projects.each_with_object({}) do |project, hash|
|
|
148
|
+
hash[project.key] = {
|
|
149
|
+
id: project.linear_id,
|
|
150
|
+
name: project.name,
|
|
151
|
+
state: project.state_type
|
|
152
|
+
}
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def export_users
|
|
157
|
+
LinearApi::CachedMetadata.users.each_with_object({}) do |user, hash|
|
|
158
|
+
hash[user.key] = {
|
|
159
|
+
id: user.linear_id,
|
|
160
|
+
name: user.name
|
|
161
|
+
}
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: linear_api
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.3.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- TheOwnerStack
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: faraday
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.0'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '3.0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '1.0'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '3.0'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: rails
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '7.0'
|
|
39
|
+
type: :runtime
|
|
40
|
+
prerelease: false
|
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
42
|
+
requirements:
|
|
43
|
+
- - ">="
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '7.0'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: bundler
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - "~>"
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '2.0'
|
|
53
|
+
type: :development
|
|
54
|
+
prerelease: false
|
|
55
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - "~>"
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '2.0'
|
|
60
|
+
- !ruby/object:Gem::Dependency
|
|
61
|
+
name: dotenv
|
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
|
63
|
+
requirements:
|
|
64
|
+
- - "~>"
|
|
65
|
+
- !ruby/object:Gem::Version
|
|
66
|
+
version: '3.0'
|
|
67
|
+
type: :development
|
|
68
|
+
prerelease: false
|
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - "~>"
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '3.0'
|
|
74
|
+
- !ruby/object:Gem::Dependency
|
|
75
|
+
name: factory_bot_rails
|
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - "~>"
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: '6.4'
|
|
81
|
+
type: :development
|
|
82
|
+
prerelease: false
|
|
83
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - "~>"
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '6.4'
|
|
88
|
+
- !ruby/object:Gem::Dependency
|
|
89
|
+
name: rake
|
|
90
|
+
requirement: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - "~>"
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '13.0'
|
|
95
|
+
type: :development
|
|
96
|
+
prerelease: false
|
|
97
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
99
|
+
- - "~>"
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '13.0'
|
|
102
|
+
- !ruby/object:Gem::Dependency
|
|
103
|
+
name: rspec
|
|
104
|
+
requirement: !ruby/object:Gem::Requirement
|
|
105
|
+
requirements:
|
|
106
|
+
- - "~>"
|
|
107
|
+
- !ruby/object:Gem::Version
|
|
108
|
+
version: '3.12'
|
|
109
|
+
type: :development
|
|
110
|
+
prerelease: false
|
|
111
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
112
|
+
requirements:
|
|
113
|
+
- - "~>"
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: '3.12'
|
|
116
|
+
- !ruby/object:Gem::Dependency
|
|
117
|
+
name: rspec-rails
|
|
118
|
+
requirement: !ruby/object:Gem::Requirement
|
|
119
|
+
requirements:
|
|
120
|
+
- - "~>"
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: '6.1'
|
|
123
|
+
type: :development
|
|
124
|
+
prerelease: false
|
|
125
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
126
|
+
requirements:
|
|
127
|
+
- - "~>"
|
|
128
|
+
- !ruby/object:Gem::Version
|
|
129
|
+
version: '6.1'
|
|
130
|
+
- !ruby/object:Gem::Dependency
|
|
131
|
+
name: rubocop
|
|
132
|
+
requirement: !ruby/object:Gem::Requirement
|
|
133
|
+
requirements:
|
|
134
|
+
- - "~>"
|
|
135
|
+
- !ruby/object:Gem::Version
|
|
136
|
+
version: '1.50'
|
|
137
|
+
type: :development
|
|
138
|
+
prerelease: false
|
|
139
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
140
|
+
requirements:
|
|
141
|
+
- - "~>"
|
|
142
|
+
- !ruby/object:Gem::Version
|
|
143
|
+
version: '1.50'
|
|
144
|
+
- !ruby/object:Gem::Dependency
|
|
145
|
+
name: rubocop-rspec
|
|
146
|
+
requirement: !ruby/object:Gem::Requirement
|
|
147
|
+
requirements:
|
|
148
|
+
- - "~>"
|
|
149
|
+
- !ruby/object:Gem::Version
|
|
150
|
+
version: '2.20'
|
|
151
|
+
type: :development
|
|
152
|
+
prerelease: false
|
|
153
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
154
|
+
requirements:
|
|
155
|
+
- - "~>"
|
|
156
|
+
- !ruby/object:Gem::Version
|
|
157
|
+
version: '2.20'
|
|
158
|
+
- !ruby/object:Gem::Dependency
|
|
159
|
+
name: simplecov
|
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
|
161
|
+
requirements:
|
|
162
|
+
- - "~>"
|
|
163
|
+
- !ruby/object:Gem::Version
|
|
164
|
+
version: '0.22'
|
|
165
|
+
type: :development
|
|
166
|
+
prerelease: false
|
|
167
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
168
|
+
requirements:
|
|
169
|
+
- - "~>"
|
|
170
|
+
- !ruby/object:Gem::Version
|
|
171
|
+
version: '0.22'
|
|
172
|
+
- !ruby/object:Gem::Dependency
|
|
173
|
+
name: sqlite3
|
|
174
|
+
requirement: !ruby/object:Gem::Requirement
|
|
175
|
+
requirements:
|
|
176
|
+
- - ">="
|
|
177
|
+
- !ruby/object:Gem::Version
|
|
178
|
+
version: '2.1'
|
|
179
|
+
type: :development
|
|
180
|
+
prerelease: false
|
|
181
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
182
|
+
requirements:
|
|
183
|
+
- - ">="
|
|
184
|
+
- !ruby/object:Gem::Version
|
|
185
|
+
version: '2.1'
|
|
186
|
+
- !ruby/object:Gem::Dependency
|
|
187
|
+
name: vcr
|
|
188
|
+
requirement: !ruby/object:Gem::Requirement
|
|
189
|
+
requirements:
|
|
190
|
+
- - "~>"
|
|
191
|
+
- !ruby/object:Gem::Version
|
|
192
|
+
version: '6.0'
|
|
193
|
+
type: :development
|
|
194
|
+
prerelease: false
|
|
195
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
196
|
+
requirements:
|
|
197
|
+
- - "~>"
|
|
198
|
+
- !ruby/object:Gem::Version
|
|
199
|
+
version: '6.0'
|
|
200
|
+
- !ruby/object:Gem::Dependency
|
|
201
|
+
name: webmock
|
|
202
|
+
requirement: !ruby/object:Gem::Requirement
|
|
203
|
+
requirements:
|
|
204
|
+
- - "~>"
|
|
205
|
+
- !ruby/object:Gem::Version
|
|
206
|
+
version: '3.18'
|
|
207
|
+
type: :development
|
|
208
|
+
prerelease: false
|
|
209
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
210
|
+
requirements:
|
|
211
|
+
- - "~>"
|
|
212
|
+
- !ruby/object:Gem::Version
|
|
213
|
+
version: '3.18'
|
|
214
|
+
description: A Ruby gem for interacting with the Linear project management API. Supports
|
|
215
|
+
creating, updating, and querying issues, projects, and labels. Includes a Rails
|
|
216
|
+
Engine for database-backed issue tracking and caching.
|
|
217
|
+
email:
|
|
218
|
+
- dev@theownerstack.com
|
|
219
|
+
executables: []
|
|
220
|
+
extensions: []
|
|
221
|
+
extra_rdoc_files: []
|
|
222
|
+
files:
|
|
223
|
+
- CHANGELOG.md
|
|
224
|
+
- LICENSE.txt
|
|
225
|
+
- README.md
|
|
226
|
+
- app/models/linear_api/application_record.rb
|
|
227
|
+
- app/models/linear_api/cached_metadata.rb
|
|
228
|
+
- app/models/linear_api/synced_issue.rb
|
|
229
|
+
- db/migrate/20260204000001_create_linear_api_cached_metadata.rb
|
|
230
|
+
- db/migrate/20260204000002_create_linear_api_synced_issues.rb
|
|
231
|
+
- lib/linear_api.rb
|
|
232
|
+
- lib/linear_api/cache_sync.rb
|
|
233
|
+
- lib/linear_api/client.rb
|
|
234
|
+
- lib/linear_api/engine.rb
|
|
235
|
+
- lib/linear_api/issue.rb
|
|
236
|
+
- lib/linear_api/issue_tracker.rb
|
|
237
|
+
- lib/linear_api/label.rb
|
|
238
|
+
- lib/linear_api/project.rb
|
|
239
|
+
- lib/linear_api/result.rb
|
|
240
|
+
- lib/linear_api/team.rb
|
|
241
|
+
- lib/linear_api/version.rb
|
|
242
|
+
- lib/tasks/linear_api.rake
|
|
243
|
+
homepage: https://github.com/dan1d/linear_api
|
|
244
|
+
licenses:
|
|
245
|
+
- MIT
|
|
246
|
+
metadata:
|
|
247
|
+
homepage_uri: https://github.com/dan1d/linear_api
|
|
248
|
+
source_code_uri: https://github.com/dan1d/linear_api
|
|
249
|
+
changelog_uri: https://github.com/dan1d/linear_api/blob/main/CHANGELOG.md
|
|
250
|
+
rubygems_mfa_required: 'true'
|
|
251
|
+
rdoc_options: []
|
|
252
|
+
require_paths:
|
|
253
|
+
- lib
|
|
254
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
255
|
+
requirements:
|
|
256
|
+
- - ">="
|
|
257
|
+
- !ruby/object:Gem::Version
|
|
258
|
+
version: 3.0.0
|
|
259
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
260
|
+
requirements:
|
|
261
|
+
- - ">="
|
|
262
|
+
- !ruby/object:Gem::Version
|
|
263
|
+
version: '0'
|
|
264
|
+
requirements: []
|
|
265
|
+
rubygems_version: 3.6.9
|
|
266
|
+
specification_version: 4
|
|
267
|
+
summary: Ruby client for the Linear GraphQL API with Rails Engine support
|
|
268
|
+
test_files: []
|