linear-rb 0.2.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1da26699f5a96c66c0ab9eaff87b6d6b0af051810e289ba0fd7474d5874c2e8d
4
- data.tar.gz: 61c18f121fc85cd46821d4291f49021cd2d2e9334e0b75ec8d54fffb4b16f840
3
+ metadata.gz: 2d86a47411e5f3e9ab46945cded06b74c305fee7552ac4770f6c93023dddb3dd
4
+ data.tar.gz: 8b8aa4987546fc77b34b7addab90d6181aa6b13b8d5fa1f7a32ce96d5c2814ef
5
5
  SHA512:
6
- metadata.gz: ff8b25a4e714cc5dc5b5db510912f4eb1a157ee9f1e7289166de519797fd9a4eb1008bf4d44dc38ad16456a6a43116ade1b2b9f8893f810e12f58c358dde5efd
7
- data.tar.gz: 2a1fa04804fa329fc0cb8d1e73c926cc08e7b290d6eadc88dff4baae898f0007f861f30fc2a0c321bb39f0de505ff95ca5f6b59f0e7fca9a6380f01cb0d08ea0
6
+ metadata.gz: 89a95415e7aa7cc0d9f605eeb37d1444bd604fcb321cb182cb13b5f60410c35b95ff39836574462c56b4682c3a117fa7fcbeef8e0cfcad709fed91ab052b5e29
7
+ data.tar.gz: 7888ac607e72ae1480d9364bf0034acbe789e7bd6e7f4fa047b2e12cbce7dd626e0920d08c3d0aa1cc104aa92d0c2fb57632b46d0fb38506cb47b5bd471bc740
data/bin/linear CHANGED
@@ -14,7 +14,10 @@ def show_usage
14
14
  linear teams List all teams
15
15
  linear projects List all projects
16
16
  linear comment ISSUE_ID COMMENT Add a comment to an issue
17
- linear update ISSUE_ID STATE Update issue state
17
+ linear update ISSUE_ID [OPTIONS] Update issue (at least one option required)
18
+ --state STATE Update issue state
19
+ --title TITLE Update issue title
20
+ --description DESCRIPTION Update issue description
18
21
 
19
22
  Issues Filters (all optional, can be combined):
20
23
  --query TEXT Search by title text
@@ -49,8 +52,13 @@ def show_usage
49
52
  # Other commands
50
53
  linear teams
51
54
  linear projects
52
- linear comment FAT-85 "This is done"
53
- linear update FAT-85 "Done"
55
+ linear comment DEV-85 "This is done"
56
+
57
+ # Update issue
58
+ linear update DEV-85 --state "Done"
59
+ linear update DEV-85 --title "New title"
60
+ linear update DEV-85 --description "Updated description"
61
+ linear update DEV-85 --state "In Progress" --title "Working on it" --description "Started implementation"
54
62
 
55
63
  Configuration:
56
64
  Set the LINEAR_API_KEY environment variable with your API key from:
@@ -135,16 +143,27 @@ when 'comment'
135
143
 
136
144
  when 'update'
137
145
  issue_id = ARGV.shift
138
- state_name = ARGV.shift
139
146
 
140
- if issue_id.nil? || issue_id.empty? || state_name.nil? || state_name.empty?
141
- puts "Error: issue ID and state name required"
142
- puts "Usage: linear update ISSUE_ID \"State Name\""
147
+ if issue_id.nil? || issue_id.empty?
148
+ puts "Error: issue ID required"
149
+ puts "Usage: linear update ISSUE_ID [--state STATE] [--title TITLE] [--description DESCRIPTION]"
143
150
  exit 1
144
151
  end
145
152
 
153
+ options = {}
154
+ OptionParser.new do |opts|
155
+ opts.on("--state STATE", "Update issue state") { |v| options[:state] = v }
156
+ opts.on("--title TITLE", "Update issue title") { |v| options[:title] = v }
157
+ opts.on("--description DESCRIPTION", "Update issue description") { |v| options[:description] = v }
158
+ end.parse!
159
+
146
160
  begin
147
- Linear::Commands.update_issue_state(issue_id, state_name)
161
+ Linear::Commands.update_issue(
162
+ issue_id,
163
+ state: options[:state],
164
+ title: options[:title],
165
+ description: options[:description]
166
+ )
148
167
  rescue => e
149
168
  puts "Error: #{e.message}"
150
169
  exit 1
@@ -83,8 +83,14 @@ module Linear
83
83
  end
84
84
  end
85
85
 
86
- def update_issue_state(issue_id, state_name, client: Client.new)
87
- # Get the issue details including team
86
+ def update_issue(issue_id, state: nil, title: nil, description: nil, client: Client.new)
87
+ # 1. Validate at least one change provided
88
+ if state.nil? && title.nil? && description.nil?
89
+ puts "Error: At least one of --state, --title, or --description must be provided"
90
+ return
91
+ end
92
+
93
+ # 2. Fetch issue to get internal UUID
88
94
  issue_result = client.query(Queries::ISSUE, { id: issue_id })
89
95
  issue = issue_result.dig("data", "issue")
90
96
 
@@ -93,65 +99,51 @@ module Linear
93
99
  return
94
100
  end
95
101
 
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
102
+ # 3. If state provided, resolve state ID (existing logic)
103
+ state_id = nil
104
+ target_state = nil
105
+ if state
106
+ team_key = issue_id.split('-').first
107
+ teams_result = client.query(Queries::TEAMS)
108
+ teams = teams_result.dig("data", "teams", "nodes") || []
109
+ team = teams.find { |t| t['key'] == team_key }
108
110
 
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 }
111
+ unless team
112
+ puts "Error: Team not found for issue #{issue_id}"
113
+ return
114
+ end
115
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
116
+ states_result = client.query(Queries::WORKFLOW_STATES, { teamId: team['id'] })
117
+ states = states_result.dig("data", "team", "states", "nodes") || []
118
+ target_state = states.find { |s| s['name'].downcase == state.downcase }
121
119
 
122
- # Update the issue
123
- result = client.query(Queries::UPDATE_ISSUE, {
124
- issueId: issue['id'],
125
- stateId: target_state['id']
126
- })
120
+ unless target_state
121
+ puts "Error: State '#{state}' not found. Available states:"
122
+ states.each { |s| puts " - #{s['name']}" }
123
+ return
124
+ end
127
125
 
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"
126
+ state_id = target_state['id']
132
127
  end
133
- end
134
128
 
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")
129
+ # 4. Build mutation parameters
130
+ params = { issueId: issue['id'] }
131
+ params[:stateId] = state_id if state_id
132
+ params[:title] = title if title
133
+ params[:description] = description if description
139
134
 
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
- })
135
+ # 5. Execute mutation
136
+ result = client.query(Queries::UPDATE_ISSUE, params)
150
137
 
138
+ # 6. Display results
151
139
  if result.dig("data", "issueUpdate", "success")
152
- puts "Updated #{issue_id} description"
140
+ changes = []
141
+ changes << "state to '#{target_state['name']}'" if state
142
+ changes << "title" if title
143
+ changes << "description" if description
144
+ puts "Updated #{issue_id}: #{changes.join(', ')}"
153
145
  else
154
- puts "Error: Failed to update issue description"
146
+ puts "Error: Failed to update issue"
155
147
  end
156
148
  end
157
149
 
@@ -127,15 +127,17 @@ module Linear
127
127
  GQL
128
128
 
129
129
  UPDATE_ISSUE = <<~GQL
130
- mutation($issueId: String!, $stateId: String, $description: String) {
130
+ mutation($issueId: String!, $stateId: String, $description: String, $title: String) {
131
131
  issueUpdate(id: $issueId, input: {
132
132
  stateId: $stateId
133
133
  description: $description
134
+ title: $title
134
135
  }) {
135
136
  success
136
137
  issue {
137
138
  id
138
139
  identifier
140
+ title
139
141
  state {
140
142
  name
141
143
  }
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.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Kinkead