linear-rb 0.2.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1da26699f5a96c66c0ab9eaff87b6d6b0af051810e289ba0fd7474d5874c2e8d
4
- data.tar.gz: 61c18f121fc85cd46821d4291f49021cd2d2e9334e0b75ec8d54fffb4b16f840
3
+ metadata.gz: f3e9c972a48cc50b483ca7b2b0add3aaaff8d6db08c421964e9f8cad348f8f95
4
+ data.tar.gz: dd874783401a2a38cc14d1febddaf2271f2ff75201797b5a84b9c67177244913
5
5
  SHA512:
6
- metadata.gz: ff8b25a4e714cc5dc5b5db510912f4eb1a157ee9f1e7289166de519797fd9a4eb1008bf4d44dc38ad16456a6a43116ade1b2b9f8893f810e12f58c358dde5efd
7
- data.tar.gz: 2a1fa04804fa329fc0cb8d1e73c926cc08e7b290d6eadc88dff4baae898f0007f861f30fc2a0c321bb39f0de505ff95ca5f6b59f0e7fca9a6380f01cb0d08ea0
6
+ metadata.gz: 46ef93d456c996f850892082b45bd753e51874b451d6d528d4d5a8d8b1deebcf0fa49d956baf7a6ae0bc626beb8128b2f9219c79ff1c29e30fc78a9a5cce0e27
7
+ data.tar.gz: 003a97d70f58e93d3ccb0a2b6152e7936c9dd2abefc277d9ab20bdc646eec8e919c7b649b2875cb18b1dedf54994fc005e02fa2182845648c068b0a068559682
data/bin/linear CHANGED
@@ -13,6 +13,7 @@ def show_usage
13
13
  linear mine Show issues assigned to you
14
14
  linear teams List all teams
15
15
  linear projects List all projects
16
+ linear create [OPTIONS] Create a new issue
16
17
  linear comment ISSUE_ID COMMENT Add a comment to an issue
17
18
  linear update ISSUE_ID STATE Update issue state
18
19
 
@@ -22,6 +23,14 @@ def show_usage
22
23
  --state STATE Filter by state name (case-insensitive)
23
24
  --team TEAM_KEY Filter by team key
24
25
 
26
+ Create Issue Options:
27
+ --team TEAM_KEY Team key (required)
28
+ --title "TITLE" Issue title (required)
29
+ --description "DESC" Issue description (optional)
30
+ --priority PRIORITY Priority: 0=None, 1=Urgent, 2=High, 3=Medium, 4=Low (optional)
31
+ --state "STATE" State name (optional)
32
+ --project PROJECT_ID Project ID (optional)
33
+
25
34
  Examples:
26
35
  # View a specific issue
27
36
  linear issue ENG-123
@@ -46,6 +55,11 @@ def show_usage
46
55
  # Your assigned issues
47
56
  linear mine
48
57
 
58
+ # Create a new issue
59
+ linear create --team ENG --title "Fix login bug"
60
+ linear create --team ENG --title "Add dark mode" --description "Users want dark mode" --priority 2
61
+ linear create --team ENG --title "Refactor API" --state "In Progress" --priority 3
62
+
49
63
  # Other commands
50
64
  linear teams
51
65
  linear projects
@@ -150,6 +164,31 @@ when 'update'
150
164
  exit 1
151
165
  end
152
166
 
167
+ when 'create'
168
+ options = {}
169
+ OptionParser.new do |opts|
170
+ opts.on("--team TEAM", "Team key (required)") { |v| options[:team] = v }
171
+ opts.on("--title TITLE", "Issue title (required)") { |v| options[:title] = v }
172
+ opts.on("--description DESC", "Issue description") { |v| options[:description] = v }
173
+ opts.on("--priority PRIORITY", "Priority (0-4)") { |v| options[:priority] = v }
174
+ opts.on("--state STATE", "State name") { |v| options[:state] = v }
175
+ opts.on("--assignee EMAIL", "Assignee email") { |v| options[:assignee] = v }
176
+ opts.on("--project PROJECT", "Project ID") { |v| options[:project] = v }
177
+ end.parse!
178
+
179
+ unless options[:team] && options[:title]
180
+ puts "Error: --team and --title are required"
181
+ puts "Usage: linear create --team TEAM --title \"Issue title\" [OPTIONS]"
182
+ exit 1
183
+ end
184
+
185
+ begin
186
+ Linear::Commands.create_issue(options)
187
+ rescue => e
188
+ puts "Error: #{e.message}"
189
+ exit 1
190
+ end
191
+
153
192
  when 'help', '--help', '-h', nil
154
193
  show_usage
155
194
 
@@ -0,0 +1,29 @@
1
+ module Linear
2
+ module Commands
3
+ module AddComment
4
+ extend self
5
+
6
+ def add_comment(issue_id, body, client: Client.new)
7
+ # First get the issue to get its internal ID
8
+ issue_result = client.query(Queries::ISSUE, { id: issue_id })
9
+ issue = issue_result.dig("data", "issue")
10
+
11
+ unless issue
12
+ puts "Error: Issue not found: #{issue_id}"
13
+ return
14
+ end
15
+
16
+ result = client.query(Queries::CREATE_COMMENT, {
17
+ issueId: issue['id'],
18
+ body: body
19
+ })
20
+
21
+ if result.dig("data", "commentCreate", "success")
22
+ puts "Comment added to #{issue_id}"
23
+ else
24
+ puts "Error: Failed to add comment"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,67 @@
1
+ module Linear
2
+ module Commands
3
+ module CreateIssue
4
+ extend self
5
+
6
+ def create_issue(options, client: Client.new)
7
+ # Get team ID from team key
8
+ teams_result = client.query(Queries::TEAMS)
9
+ teams = teams_result.dig("data", "teams", "nodes") || []
10
+ team = teams.find { |t| t['key'].upcase == options[:team].upcase }
11
+
12
+ unless team
13
+ puts "Error: Team '#{options[:team]}' not found. Available teams:"
14
+ teams.each { |t| puts " #{t['key']} - #{t['name']}" }
15
+ return
16
+ end
17
+
18
+ variables = {
19
+ teamId: team['id'],
20
+ title: options[:title]
21
+ }
22
+
23
+ # Add optional description
24
+ variables[:description] = options[:description] if options[:description]
25
+
26
+ # Add optional project
27
+ variables[:projectId] = options[:project] if options[:project]
28
+
29
+ # Handle priority (convert string to integer if needed)
30
+ if options[:priority]
31
+ variables[:priority] = options[:priority].to_i
32
+ end
33
+
34
+ # Handle state (need to look up state ID from name)
35
+ if options[:state]
36
+ states_result = client.query(Queries::WORKFLOW_STATES, { teamId: team['id'] })
37
+ states = states_result.dig("data", "team", "states", "nodes") || []
38
+ target_state = states.find { |s| s['name'].downcase == options[:state].downcase }
39
+
40
+ if target_state
41
+ variables[:stateId] = target_state['id']
42
+ else
43
+ puts "Warning: State '#{options[:state]}' not found, using default"
44
+ end
45
+ end
46
+
47
+ # Handle assignee (need to look up user ID from email)
48
+ if options[:assignee]
49
+ # Would need a new USER_BY_EMAIL query
50
+ puts "Warning: Assignee lookup not yet implemented"
51
+ end
52
+
53
+ # Create the issue
54
+ result = client.query(Queries::CREATE_ISSUE, variables)
55
+
56
+ if result.dig("data", "issueCreate", "success")
57
+ issue = result.dig("data", "issueCreate", "issue")
58
+ puts "Created issue: #{issue['identifier']}"
59
+ puts "Title: #{issue['title']}"
60
+ puts "URL: #{issue['url']}"
61
+ else
62
+ puts "Error: Failed to create issue"
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,18 @@
1
+ module Linear
2
+ module Commands
3
+ module FetchIssue
4
+ extend self
5
+
6
+ def fetch_issue(issue_id, client: Client.new)
7
+ result = client.query(Queries::ISSUE, { id: issue_id })
8
+
9
+ issue = result.dig("data", "issue")
10
+ if issue
11
+ Formatters.display_issue(issue)
12
+ else
13
+ puts "Issue not found: #{issue_id}"
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ module Linear
2
+ module Commands
3
+ module ListIssues
4
+ extend self
5
+
6
+ def list_issues(options = {}, client: Client.new)
7
+ filter = {}
8
+ filter[:title] = { contains: options[:query] } if options[:query]
9
+ filter[:project] = { id: { eq: options[:project] } } if options[:project]
10
+ filter[:state] = { name: { eqIgnoreCase: options[:state] } } if options[:state]
11
+ filter[:team] = { key: { eq: options[:team] } } if options[:team]
12
+
13
+ result = client.query(Queries::LIST_ISSUES, { filter: filter })
14
+
15
+ issues = result.dig("data", "issues", "nodes") || []
16
+ if issues.empty?
17
+ puts "No issues found"
18
+ else
19
+ Formatters.display_issue_list(issues)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ module Linear
2
+ module Commands
3
+ module ListProjects
4
+ extend self
5
+
6
+ def list_projects(client: Client.new)
7
+ result = client.query(Queries::PROJECTS)
8
+
9
+ projects = result.dig("data", "projects", "nodes") || []
10
+ if projects.empty?
11
+ puts "No projects found"
12
+ else
13
+ Formatters.display_project_list(projects)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module Linear
2
+ module Commands
3
+ module ListTeams
4
+ extend self
5
+
6
+ def list_teams(client: Client.new)
7
+ result = client.query(Queries::TEAMS)
8
+
9
+ teams = result.dig("data", "teams", "nodes") || []
10
+ teams.each do |team|
11
+ puts "#{team['key'].ljust(10)} #{team['name']}"
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module Linear
2
+ module Commands
3
+ module MyIssues
4
+ extend self
5
+
6
+ def my_issues(client: Client.new)
7
+ result = client.query(Queries::MY_ISSUES)
8
+
9
+ issues = result.dig("data", "viewer", "assignedIssues", "nodes") || []
10
+ if issues.empty?
11
+ puts "No issues assigned to you"
12
+ else
13
+ Formatters.display_issue_list(issues)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ module Linear
2
+ module Commands
3
+ module UpdateIssueDescription
4
+ extend self
5
+
6
+ def update_issue_description(issue_id, description, client: Client.new)
7
+ # Get the issue to get its internal ID
8
+ issue_result = client.query(Queries::ISSUE, { id: issue_id })
9
+ issue = issue_result.dig("data", "issue")
10
+
11
+ unless issue
12
+ puts "Error: Issue not found: #{issue_id}"
13
+ return
14
+ end
15
+
16
+ # Update the issue description
17
+ result = client.query(Queries::UPDATE_ISSUE, {
18
+ issueId: issue['id'],
19
+ description: description
20
+ })
21
+
22
+ if result.dig("data", "issueUpdate", "success")
23
+ puts "Updated #{issue_id} description"
24
+ else
25
+ puts "Error: Failed to update issue description"
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,56 @@
1
+ module Linear
2
+ module Commands
3
+ module UpdateIssueState
4
+ extend self
5
+
6
+ def update_issue_state(issue_id, state_name, client: Client.new)
7
+ # Get the issue details including team
8
+ issue_result = client.query(Queries::ISSUE, { id: issue_id })
9
+ issue = issue_result.dig("data", "issue")
10
+
11
+ unless issue
12
+ puts "Error: Issue not found: #{issue_id}"
13
+ return
14
+ end
15
+
16
+ # Get team states - need to find team ID first
17
+ teams_result = client.query(Queries::TEAMS)
18
+ teams = teams_result.dig("data", "teams", "nodes") || []
19
+
20
+ # Find the team from the issue identifier prefix (e.g., "FAT" from "FAT-85")
21
+ team_key = issue_id.split('-').first
22
+ team = teams.find { |t| t['key'] == team_key }
23
+
24
+ unless team
25
+ puts "Error: Team not found for issue #{issue_id}"
26
+ return
27
+ end
28
+
29
+ # Get workflow states for the team
30
+ states_result = client.query(Queries::WORKFLOW_STATES, { teamId: team['id'] })
31
+ states = states_result.dig("data", "team", "states", "nodes") || []
32
+
33
+ # Find the state by name (case-insensitive)
34
+ target_state = states.find { |s| s['name'].downcase == state_name.downcase }
35
+
36
+ unless target_state
37
+ puts "Error: State '#{state_name}' not found. Available states:"
38
+ states.each { |s| puts " - #{s['name']}" }
39
+ return
40
+ end
41
+
42
+ # Update the issue
43
+ result = client.query(Queries::UPDATE_ISSUE, {
44
+ issueId: issue['id'],
45
+ stateId: target_state['id']
46
+ })
47
+
48
+ if result.dig("data", "issueUpdate", "success")
49
+ puts "Updated #{issue_id} to '#{target_state['name']}'"
50
+ else
51
+ puts "Error: Failed to update issue state"
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,220 +1,32 @@
1
+ require_relative "commands/fetch_issue"
2
+ require_relative "commands/list_issues"
3
+ require_relative "commands/my_issues"
4
+ require_relative "commands/list_teams"
5
+ require_relative "commands/list_projects"
6
+ require_relative "commands/add_comment"
7
+ require_relative "commands/update_issue_state"
8
+ require_relative "commands/update_issue_description"
9
+ require_relative "commands/create_issue"
10
+
1
11
  module Linear
2
12
  module Commands
3
13
  extend self
4
14
 
5
- def fetch_issue(issue_id, client: Client.new)
6
- result = client.query(Queries::ISSUE, { id: issue_id })
7
-
8
- issue = result.dig("data", "issue")
9
- if issue
10
- display_issue(issue)
11
- else
12
- puts "Issue not found: #{issue_id}"
13
- end
14
- end
15
-
16
- def list_issues(options = {}, client: Client.new)
17
- filter = {}
18
- filter[:title] = { contains: options[:query] } if options[:query]
19
- filter[:project] = { id: { eq: options[:project] } } if options[:project]
20
- filter[:state] = { name: { eqIgnoreCase: options[:state] } } if options[:state]
21
- filter[:team] = { key: { eq: options[:team] } } if options[:team]
22
-
23
- result = client.query(Queries::LIST_ISSUES, { filter: filter })
24
-
25
- issues = result.dig("data", "issues", "nodes") || []
26
- if issues.empty?
27
- puts "No issues found"
28
- else
29
- display_issue_list(issues)
30
- end
31
- end
32
-
33
- def my_issues(client: Client.new)
34
- result = client.query(Queries::MY_ISSUES)
35
-
36
- issues = result.dig("data", "viewer", "assignedIssues", "nodes") || []
37
- if issues.empty?
38
- puts "No issues assigned to you"
39
- else
40
- display_issue_list(issues)
41
- end
42
- end
43
-
44
- def list_teams(client: Client.new)
45
- result = client.query(Queries::TEAMS)
46
-
47
- teams = result.dig("data", "teams", "nodes") || []
48
- teams.each do |team|
49
- puts "#{team['key'].ljust(10)} #{team['name']}"
50
- end
51
- end
52
-
53
- def list_projects(client: Client.new)
54
- result = client.query(Queries::PROJECTS)
55
-
56
- projects = result.dig("data", "projects", "nodes") || []
57
- if projects.empty?
58
- puts "No projects found"
59
- else
60
- display_project_list(projects)
61
- end
62
- end
63
-
64
- def add_comment(issue_id, body, client: Client.new)
65
- # First get the issue to get its internal ID
66
- issue_result = client.query(Queries::ISSUE, { id: issue_id })
67
- issue = issue_result.dig("data", "issue")
68
-
69
- unless issue
70
- puts "Error: Issue not found: #{issue_id}"
71
- return
72
- end
73
-
74
- result = client.query(Queries::CREATE_COMMENT, {
75
- issueId: issue['id'],
76
- body: body
77
- })
78
-
79
- if result.dig("data", "commentCreate", "success")
80
- puts "Comment added to #{issue_id}"
81
- else
82
- puts "Error: Failed to add comment"
83
- end
84
- end
85
-
86
- def update_issue_state(issue_id, state_name, client: Client.new)
87
- # Get the issue details including team
88
- issue_result = client.query(Queries::ISSUE, { id: issue_id })
89
- issue = issue_result.dig("data", "issue")
90
-
91
- unless issue
92
- puts "Error: Issue not found: #{issue_id}"
93
- return
94
- end
95
-
96
- # Get team states - need to find team ID first
97
- teams_result = client.query(Queries::TEAMS)
98
- teams = teams_result.dig("data", "teams", "nodes") || []
99
-
100
- # Find the team from the issue identifier prefix (e.g., "FAT" from "FAT-85")
101
- team_key = issue_id.split('-').first
102
- team = teams.find { |t| t['key'] == team_key }
103
-
104
- unless team
105
- puts "Error: Team not found for issue #{issue_id}"
106
- return
107
- end
108
-
109
- # Get workflow states for the team
110
- states_result = client.query(Queries::WORKFLOW_STATES, { teamId: team['id'] })
111
- states = states_result.dig("data", "team", "states", "nodes") || []
112
-
113
- # Find the state by name (case-insensitive)
114
- target_state = states.find { |s| s['name'].downcase == state_name.downcase }
115
-
116
- unless target_state
117
- puts "Error: State '#{state_name}' not found. Available states:"
118
- states.each { |s| puts " - #{s['name']}" }
119
- return
120
- end
121
-
122
- # Update the issue
123
- result = client.query(Queries::UPDATE_ISSUE, {
124
- issueId: issue['id'],
125
- stateId: target_state['id']
126
- })
127
-
128
- if result.dig("data", "issueUpdate", "success")
129
- puts "Updated #{issue_id} to '#{target_state['name']}'"
130
- else
131
- puts "Error: Failed to update issue state"
132
- end
133
- end
134
-
135
- def update_issue_description(issue_id, description, client: Client.new)
136
- # Get the issue to get its internal ID
137
- issue_result = client.query(Queries::ISSUE, { id: issue_id })
138
- issue = issue_result.dig("data", "issue")
139
-
140
- unless issue
141
- puts "Error: Issue not found: #{issue_id}"
142
- return
143
- end
144
-
145
- # Update the issue description
146
- result = client.query(Queries::UPDATE_ISSUE, {
147
- issueId: issue['id'],
148
- description: description
149
- })
150
-
151
- if result.dig("data", "issueUpdate", "success")
152
- puts "Updated #{issue_id} description"
153
- else
154
- puts "Error: Failed to update issue description"
155
- end
156
- end
157
-
158
- private
159
-
160
- def display_issue(issue)
161
- puts "\n#{issue['identifier']}: #{issue['title']}"
162
- puts "=" * 60
163
- puts "Status: #{issue['state']['name']}"
164
- puts "Assignee: #{issue.dig('assignee', 'name') || 'Unassigned'}"
165
- puts "Priority: #{priority_label(issue['priority'])}"
166
- puts "URL: #{issue['url']}"
167
- puts "\nDescription:"
168
- puts issue['description'] || "(no description)"
169
- puts ""
170
- end
171
-
172
- def display_issue_list(issues)
173
- puts "\nFound #{issues.length} issue(s):\n\n"
174
- issues.each do |issue|
175
- state_badge = "[#{issue['state']['name']}]".ljust(15)
176
- priority_badge = priority_label(issue['priority']).ljust(8)
177
- assignee = (issue.dig('assignee', 'name') || 'Unassigned').ljust(15)
178
-
179
- puts "#{issue['identifier'].ljust(12)} #{state_badge} #{priority_badge} #{assignee} #{issue['title']}"
180
- end
181
- puts ""
182
- end
183
-
15
+ # Include all command modules
16
+ include FetchIssue
17
+ include ListIssues
18
+ include MyIssues
19
+ include ListTeams
20
+ include ListProjects
21
+ include AddComment
22
+ include UpdateIssueState
23
+ include UpdateIssueDescription
24
+ include CreateIssue
25
+
26
+ # Expose formatters for backward compatibility
184
27
  def priority_label(priority)
185
- case priority
186
- when 0 then "None"
187
- when 1 then "Urgent"
188
- when 2 then "High"
189
- when 3 then "Medium"
190
- when 4 then "Low"
191
- else "Unknown"
192
- end
193
- end
194
-
195
- def display_project_list(projects)
196
- puts "\nFound #{projects.length} project(s):\n\n"
197
- projects.each do |project|
198
- state_badge = "[#{project['state']}]".ljust(15)
199
- progress = project['progress'] ? "#{(project['progress'] * 100).round}%" : "0%"
200
- progress_badge = progress.ljust(6)
201
- lead = (project.dig('lead', 'name') || 'No lead').ljust(20)
202
-
203
- puts "#{project['name'].ljust(30)} #{state_badge} #{progress_badge} #{lead}"
204
-
205
- if project['description'] && !project['description'].empty?
206
- # Show first line of description
207
- first_line = project['description'].lines.first&.strip
208
- puts " #{first_line[0..80]}#{'...' if first_line && first_line.length > 80}" if first_line
209
- end
210
-
211
- if project['targetDate']
212
- puts " Target: #{project['targetDate']}"
213
- end
214
-
215
- puts " URL: #{project['url']}" if project['url']
216
- puts ""
217
- end
28
+ Formatters.priority_label(priority)
218
29
  end
30
+ private :priority_label
219
31
  end
220
32
  end
@@ -0,0 +1,66 @@
1
+ module Linear
2
+ module Formatters
3
+ extend self
4
+
5
+ def display_issue(issue)
6
+ puts "\n#{issue['identifier']}: #{issue['title']}"
7
+ puts "=" * 60
8
+ puts "Status: #{issue['state']['name']}"
9
+ puts "Assignee: #{issue.dig('assignee', 'name') || 'Unassigned'}"
10
+ puts "Priority: #{priority_label(issue['priority'])}"
11
+ puts "URL: #{issue['url']}"
12
+ puts "\nDescription:"
13
+ puts issue['description'] || "(no description)"
14
+ puts ""
15
+ end
16
+
17
+ def display_issue_list(issues)
18
+ puts "\nFound #{issues.length} issue(s):\n\n"
19
+ issues.each do |issue|
20
+ state_badge = "[#{issue['state']['name']}]".ljust(15)
21
+ priority_badge = priority_label(issue['priority']).ljust(8)
22
+ assignee = (issue.dig('assignee', 'name') || 'Unassigned').ljust(15)
23
+
24
+ puts "#{issue['identifier'].ljust(12)} #{state_badge} #{priority_badge} #{assignee} #{issue['title']}"
25
+ end
26
+ puts ""
27
+ end
28
+
29
+ def priority_label(priority)
30
+ case priority
31
+ when 0 then "None"
32
+ when 1 then "Urgent"
33
+ when 2 then "High"
34
+ when 3 then "Medium"
35
+ when 4 then "Low"
36
+ else "Unknown"
37
+ end
38
+ end
39
+
40
+ def display_project_list(projects)
41
+ puts "\nFound #{projects.length} project(s):\n\n"
42
+ projects.each do |project|
43
+ state_badge = "[#{project['state']}]".ljust(15)
44
+ progress = project['progress'] ? "#{(project['progress'] * 100).round}%" : "0%"
45
+ progress_badge = progress.ljust(6)
46
+ lead = (project.dig('lead', 'name') || 'No lead').ljust(20)
47
+
48
+ puts "#{project['name'].ljust(30)} #{state_badge} #{progress_badge} #{lead}"
49
+ puts " ID: #{project['id']}"
50
+
51
+ if project['description'] && !project['description'].empty?
52
+ # Show first line of description
53
+ first_line = project['description'].lines.first&.strip
54
+ puts " #{first_line[0..80]}#{'...' if first_line && first_line.length > 80}" if first_line
55
+ end
56
+
57
+ if project['targetDate']
58
+ puts " Target: #{project['targetDate']}"
59
+ end
60
+
61
+ puts " URL: #{project['url']}" if project['url']
62
+ puts ""
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,18 @@
1
+ module Linear
2
+ module Queries
3
+ CREATE_COMMENT = <<~GQL
4
+ mutation($issueId: String!, $body: String!) {
5
+ commentCreate(input: {
6
+ issueId: $issueId
7
+ body: $body
8
+ }) {
9
+ success
10
+ comment {
11
+ id
12
+ body
13
+ }
14
+ }
15
+ }
16
+ GQL
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module Linear
2
+ module Queries
3
+ CREATE_ISSUE = <<~GQL
4
+ mutation($teamId: String!, $title: String!, $description: String, $priority: Int, $stateId: String, $assigneeId: String, $projectId: String) {
5
+ issueCreate(input: {
6
+ teamId: $teamId
7
+ title: $title
8
+ description: $description
9
+ priority: $priority
10
+ stateId: $stateId
11
+ assigneeId: $assigneeId
12
+ projectId: $projectId
13
+ }) {
14
+ success
15
+ issue {
16
+ id
17
+ identifier
18
+ title
19
+ url
20
+ }
21
+ }
22
+ }
23
+ GQL
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ module Linear
2
+ module Queries
3
+ ISSUE = <<~GQL
4
+ query($id: String!) {
5
+ issue(id: $id) {
6
+ id
7
+ identifier
8
+ title
9
+ description
10
+ state {
11
+ name
12
+ type
13
+ }
14
+ assignee {
15
+ name
16
+ email
17
+ }
18
+ priority
19
+ createdAt
20
+ updatedAt
21
+ url
22
+ }
23
+ }
24
+ GQL
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ module Linear
2
+ module Queries
3
+ LIST_ISSUES = <<~GQL
4
+ query($filter: IssueFilter!) {
5
+ issues(filter: $filter) {
6
+ nodes {
7
+ id
8
+ identifier
9
+ title
10
+ state {
11
+ name
12
+ type
13
+ }
14
+ assignee {
15
+ name
16
+ }
17
+ priority
18
+ url
19
+ }
20
+ }
21
+ }
22
+ GQL
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ module Linear
2
+ module Queries
3
+ MY_ISSUES = <<~GQL
4
+ query {
5
+ viewer {
6
+ assignedIssues {
7
+ nodes {
8
+ id
9
+ identifier
10
+ title
11
+ state {
12
+ name
13
+ type
14
+ }
15
+ priority
16
+ url
17
+ }
18
+ }
19
+ }
20
+ }
21
+ GQL
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ module Linear
2
+ module Queries
3
+ PROJECTS = <<~GQL
4
+ query {
5
+ projects {
6
+ nodes {
7
+ id
8
+ name
9
+ description
10
+ state
11
+ progress
12
+ startDate
13
+ targetDate
14
+ url
15
+ lead {
16
+ name
17
+ email
18
+ }
19
+ }
20
+ }
21
+ }
22
+ GQL
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ module Linear
2
+ module Queries
3
+ TEAMS = <<~GQL
4
+ query {
5
+ teams {
6
+ nodes {
7
+ id
8
+ key
9
+ name
10
+ }
11
+ }
12
+ }
13
+ GQL
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ module Linear
2
+ module Queries
3
+ UPDATE_ISSUE = <<~GQL
4
+ mutation($issueId: String!, $stateId: String, $description: String) {
5
+ issueUpdate(id: $issueId, input: {
6
+ stateId: $stateId
7
+ description: $description
8
+ }) {
9
+ success
10
+ issue {
11
+ id
12
+ identifier
13
+ state {
14
+ name
15
+ }
16
+ description
17
+ }
18
+ }
19
+ }
20
+ GQL
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ module Linear
2
+ module Queries
3
+ WORKFLOW_STATES = <<~GQL
4
+ query($teamId: String!) {
5
+ team(id: $teamId) {
6
+ states {
7
+ nodes {
8
+ id
9
+ name
10
+ type
11
+ }
12
+ }
13
+ }
14
+ }
15
+ GQL
16
+ end
17
+ end
@@ -1,148 +1,14 @@
1
+ require_relative "queries/issue"
2
+ require_relative "queries/list_issues"
3
+ require_relative "queries/my_issues"
4
+ require_relative "queries/teams"
5
+ require_relative "queries/projects"
6
+ require_relative "queries/workflow_states"
7
+ require_relative "queries/create_comment"
8
+ require_relative "queries/update_issue"
9
+ require_relative "queries/create_issue"
10
+
1
11
  module Linear
2
12
  module Queries
3
- ISSUE = <<~GQL
4
- query($id: String!) {
5
- issue(id: $id) {
6
- id
7
- identifier
8
- title
9
- description
10
- state {
11
- name
12
- type
13
- }
14
- assignee {
15
- name
16
- email
17
- }
18
- priority
19
- createdAt
20
- updatedAt
21
- url
22
- }
23
- }
24
- GQL
25
-
26
- LIST_ISSUES = <<~GQL
27
- query($filter: IssueFilter!) {
28
- issues(filter: $filter) {
29
- nodes {
30
- id
31
- identifier
32
- title
33
- state {
34
- name
35
- type
36
- }
37
- assignee {
38
- name
39
- }
40
- priority
41
- url
42
- }
43
- }
44
- }
45
- GQL
46
-
47
- MY_ISSUES = <<~GQL
48
- query {
49
- viewer {
50
- assignedIssues {
51
- nodes {
52
- id
53
- identifier
54
- title
55
- state {
56
- name
57
- type
58
- }
59
- priority
60
- url
61
- }
62
- }
63
- }
64
- }
65
- GQL
66
-
67
- TEAMS = <<~GQL
68
- query {
69
- teams {
70
- nodes {
71
- id
72
- key
73
- name
74
- }
75
- }
76
- }
77
- GQL
78
-
79
- PROJECTS = <<~GQL
80
- query {
81
- projects {
82
- nodes {
83
- id
84
- name
85
- description
86
- state
87
- progress
88
- startDate
89
- targetDate
90
- url
91
- lead {
92
- name
93
- email
94
- }
95
- }
96
- }
97
- }
98
- GQL
99
-
100
- WORKFLOW_STATES = <<~GQL
101
- query($teamId: String!) {
102
- team(id: $teamId) {
103
- states {
104
- nodes {
105
- id
106
- name
107
- type
108
- }
109
- }
110
- }
111
- }
112
- GQL
113
-
114
- CREATE_COMMENT = <<~GQL
115
- mutation($issueId: String!, $body: String!) {
116
- commentCreate(input: {
117
- issueId: $issueId
118
- body: $body
119
- }) {
120
- success
121
- comment {
122
- id
123
- body
124
- }
125
- }
126
- }
127
- GQL
128
-
129
- UPDATE_ISSUE = <<~GQL
130
- mutation($issueId: String!, $stateId: String, $description: String) {
131
- issueUpdate(id: $issueId, input: {
132
- stateId: $stateId
133
- description: $description
134
- }) {
135
- success
136
- issue {
137
- id
138
- identifier
139
- state {
140
- name
141
- }
142
- description
143
- }
144
- }
145
- }
146
- GQL
147
13
  end
148
14
  end
@@ -1,3 +1,3 @@
1
1
  module Linear
2
- VERSION = "0.1.0"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/linear.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require_relative "linear/version"
2
2
  require_relative "linear/client"
3
3
  require_relative "linear/queries"
4
+ require_relative "linear/formatters"
4
5
  require_relative "linear/commands"
5
6
 
6
7
  module Linear
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: linear-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Kinkead
@@ -36,7 +36,26 @@ files:
36
36
  - lib/linear.rb
37
37
  - lib/linear/client.rb
38
38
  - lib/linear/commands.rb
39
+ - lib/linear/commands/add_comment.rb
40
+ - lib/linear/commands/create_issue.rb
41
+ - lib/linear/commands/fetch_issue.rb
42
+ - lib/linear/commands/list_issues.rb
43
+ - lib/linear/commands/list_projects.rb
44
+ - lib/linear/commands/list_teams.rb
45
+ - lib/linear/commands/my_issues.rb
46
+ - lib/linear/commands/update_issue_description.rb
47
+ - lib/linear/commands/update_issue_state.rb
48
+ - lib/linear/formatters.rb
39
49
  - lib/linear/queries.rb
50
+ - lib/linear/queries/create_comment.rb
51
+ - lib/linear/queries/create_issue.rb
52
+ - lib/linear/queries/issue.rb
53
+ - lib/linear/queries/list_issues.rb
54
+ - lib/linear/queries/my_issues.rb
55
+ - lib/linear/queries/projects.rb
56
+ - lib/linear/queries/teams.rb
57
+ - lib/linear/queries/update_issue.rb
58
+ - lib/linear/queries/workflow_states.rb
40
59
  - lib/linear/version.rb
41
60
  - readme.md
42
61
  homepage: https://github.com/davekinkead/linear-rb